diff --git a/.eslintrc.js b/.eslintrc.js index 9b4b1037..79c117d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js
@@ -11,6 +11,7 @@ 'rules': { // Enabled checks. 'no-extra-semi': 'error', + 'semi': ['error', 'always'], // TODO(dpapad): Add more checks according to our styleguide. }, };
diff --git a/DEPS b/DEPS index 92cfa10..adaabf6 100644 --- a/DEPS +++ b/DEPS
@@ -44,7 +44,7 @@ # 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': '2a69daf1572f8920d156ba3f9cf60e72955d6bf2', + 'v8_revision': '20ee3efa8a86d2e9ceb835861d2251939443c7c7', # 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. @@ -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': '9a505796f3fe8c1d0cbc3f7e4e7db41fc1fde137', + 'pdfium_revision': '26cb2fa42b1a90146f9ab5c0b83ee8b48703baf4', # 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': 'e18c0f9c7950833973f15a784ff39cab7a5673c5', + 'catapult_revision': '32a3f0b8f49bb6a3e5c7f158ff7aea5584843294', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -889,6 +889,20 @@ 'src/third_party/catapult/telemetry/bin/fetch_telemetry_binary_dependencies', ], }, + + # Download checkstyle for use in PRESUBMIT for Java changes. + # TODO(jbudorick): Move this back down to the android section of hooks_os + # once it's no longer necessary for the chromium_presubmit bot. + { + 'name': 'checkstyle', + 'pattern': '.', + 'action': [ 'download_from_google_storage', + '--no_resume', + '--no_auth', + '--bucket', 'chromium-android-tools/checkstyle', + '-s', 'src/third_party/checkstyle/checkstyle-7.6.1-all.jar.sha1' + ], + }, ] # Note: These are keyed off target os, not host os. So don't move things here @@ -1088,16 +1102,6 @@ ], }, { - 'name': 'checkstyle', - 'pattern': '.', - 'action': [ 'download_from_google_storage', - '--no_resume', - '--no_auth', - '--bucket', 'chromium-android-tools/checkstyle', - '-s', 'src/third_party/checkstyle/checkstyle-7.6.1-all.jar.sha1' - ], - }, - { 'name': 'gvr_static_shim_android_arm', 'pattern': '\\.sha1', 'action': [ 'download_from_google_storage',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py index 215ffbc..7f09ce51 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py
@@ -212,6 +212,8 @@ r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$", r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$", r"^content[\\\/]test[\\\/]ppapi[\\\/]ppapi_test\.cc$", + r"^media[\\\/]cast[\\\/]test[\\\/]utility[\\\/]" + + r"standalone_cast_environment\.cc$", r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" + r"simple_platform_shared_buffer_posix\.cc$", r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
diff --git a/ash/frame/caption_buttons/frame_caption_button.cc b/ash/frame/caption_buttons/frame_caption_button.cc index ff7e5fe4..e3bd36e5 100644 --- a/ash/frame/caption_buttons/frame_caption_button.cc +++ b/ash/frame/caption_buttons/frame_caption_button.cc
@@ -101,7 +101,30 @@ return kViewClassName; } -void FrameCaptionButton::OnPaint(gfx::Canvas* canvas) { +void FrameCaptionButton::OnGestureEvent(ui::GestureEvent* event) { + // CustomButton does not become pressed when the user drags off and then back + // onto the button. Make FrameCaptionButton pressed in this case because this + // behavior is more consistent with AlternateFrameSizeButton. + if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN || + event->type() == ui::ET_GESTURE_SCROLL_UPDATE) { + if (HitTestPoint(event->location())) { + SetState(STATE_PRESSED); + RequestFocus(); + event->StopPropagation(); + } else { + SetState(STATE_NORMAL); + } + } else if (event->type() == ui::ET_GESTURE_SCROLL_END) { + if (HitTestPoint(event->location())) { + SetState(STATE_HOVERED); + NotifyClick(*event); + event->StopPropagation(); + } + } + CustomButton::OnGestureEvent(event); +} + +void FrameCaptionButton::PaintButtonContents(gfx::Canvas* canvas) { SkAlpha bg_alpha = SK_AlphaTRANSPARENT; if (hover_animation().is_animating()) bg_alpha = hover_animation().CurrentValueBetween(0, kHoveredAlpha); @@ -145,29 +168,6 @@ } } -void FrameCaptionButton::OnGestureEvent(ui::GestureEvent* event) { - // CustomButton does not become pressed when the user drags off and then back - // onto the button. Make FrameCaptionButton pressed in this case because this - // behavior is more consistent with AlternateFrameSizeButton. - if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN || - event->type() == ui::ET_GESTURE_SCROLL_UPDATE) { - if (HitTestPoint(event->location())) { - SetState(STATE_PRESSED); - RequestFocus(); - event->StopPropagation(); - } else { - SetState(STATE_NORMAL); - } - } else if (event->type() == ui::ET_GESTURE_SCROLL_END) { - if (HitTestPoint(event->location())) { - SetState(STATE_HOVERED); - NotifyClick(*event); - event->StopPropagation(); - } - } - CustomButton::OnGestureEvent(event); -} - int FrameCaptionButton::GetAlphaForIcon(int base_alpha) const { if (paint_as_active_) return base_alpha;
diff --git a/ash/frame/caption_buttons/frame_caption_button.h b/ash/frame/caption_buttons/frame_caption_button.h index 9b80522e..2d05f6ed 100644 --- a/ash/frame/caption_buttons/frame_caption_button.h +++ b/ash/frame/caption_buttons/frame_caption_button.h
@@ -48,7 +48,7 @@ // views::View overrides: const char* GetClassName() const override; - void OnPaint(gfx::Canvas* canvas) override; + void OnGestureEvent(ui::GestureEvent* event) override; void set_paint_as_active(bool paint_as_active) { paint_as_active_ = paint_as_active; @@ -60,7 +60,7 @@ protected: // views::CustomButton override: - void OnGestureEvent(ui::GestureEvent* event) override; + void PaintButtonContents(gfx::Canvas* canvas) override; private: // Determines what alpha to use for the icon based on animation and
diff --git a/ash/shelf/app_list_button.cc b/ash/shelf/app_list_button.cc index 4c4a057..584d9d8 100644 --- a/ash/shelf/app_list_button.cc +++ b/ash/shelf/app_list_button.cc
@@ -144,43 +144,6 @@ return true; } -void AppListButton::OnPaint(gfx::Canvas* canvas) { - // Call the base class first to paint any background/borders. - View::OnPaint(canvas); - - gfx::PointF circle_center(GetCenterPoint()); - - // Paint the circular background. - cc::PaintFlags bg_flags; - bg_flags.setColor(background_color_); - bg_flags.setAntiAlias(true); - bg_flags.setStyle(cc::PaintFlags::kFill_Style); - canvas->DrawCircle(circle_center, kAppListButtonRadius, bg_flags); - - // Paint a white ring as the foreground. The ceil/dsf math assures that the - // ring draws sharply and is centered at all scale factors. - const float kRingOuterRadiusDp = 7.f; - const float kRingThicknessDp = 1.5f; - - { - gfx::ScopedCanvas scoped_canvas(canvas); - const float dsf = canvas->UndoDeviceScaleFactor(); - circle_center.Scale(dsf); - - cc::PaintFlags fg_flags; - fg_flags.setAntiAlias(true); - fg_flags.setStyle(cc::PaintFlags::kStroke_Style); - fg_flags.setColor(kShelfIconColor); - const float thickness = std::ceil(kRingThicknessDp * dsf); - const float radius = std::ceil(kRingOuterRadiusDp * dsf) - thickness / 2; - fg_flags.setStrokeWidth(thickness); - // Make sure the center of the circle lands on pixel centers. - canvas->DrawCircle(circle_center, radius, fg_flags); - } - - views::Painter::PaintFocusPainter(this, canvas, focus_painter()); -} - void AppListButton::GetAccessibleNodeData(ui::AXNodeData* node_data) { node_data->role = ui::AX_ROLE_BUTTON; node_data->SetName(shelf_view_->GetTitleForView(this)); @@ -224,6 +187,38 @@ kAppListButtonRadius); } +void AppListButton::PaintButtonContents(gfx::Canvas* canvas) { + gfx::PointF circle_center(GetCenterPoint()); + + // Paint the circular background. + cc::PaintFlags bg_flags; + bg_flags.setColor(background_color_); + bg_flags.setAntiAlias(true); + bg_flags.setStyle(cc::PaintFlags::kFill_Style); + canvas->DrawCircle(circle_center, kAppListButtonRadius, bg_flags); + + // Paint a white ring as the foreground. The ceil/dsf math assures that the + // ring draws sharply and is centered at all scale factors. + const float kRingOuterRadiusDp = 7.f; + const float kRingThicknessDp = 1.5f; + + { + gfx::ScopedCanvas scoped_canvas(canvas); + const float dsf = canvas->UndoDeviceScaleFactor(); + circle_center.Scale(dsf); + + cc::PaintFlags fg_flags; + fg_flags.setAntiAlias(true); + fg_flags.setStyle(cc::PaintFlags::kStroke_Style); + fg_flags.setColor(kShelfIconColor); + const float thickness = std::ceil(kRingThicknessDp * dsf); + const float radius = std::ceil(kRingOuterRadiusDp * dsf) - thickness / 2; + fg_flags.setStrokeWidth(thickness); + // Make sure the center of the circle lands on pixel centers. + canvas->DrawCircle(circle_center, radius, fg_flags); + } +} + gfx::Point AppListButton::GetCenterPoint() const { // For a bottom-aligned shelf, the button bounds could have a larger height // than width (in the case of touch-dragging the shelf updwards) or a larger
diff --git a/ash/shelf/app_list_button.h b/ash/shelf/app_list_button.h index 31faff2..02c69c2 100644 --- a/ash/shelf/app_list_button.h +++ b/ash/shelf/app_list_button.h
@@ -42,13 +42,13 @@ void OnMouseReleased(const ui::MouseEvent& event) override; void OnMouseCaptureLost() override; bool OnMouseDragged(const ui::MouseEvent& event) override; - void OnPaint(gfx::Canvas* canvas) override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override; std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; void NotifyClick(const ui::Event& event) override; bool ShouldEnterPushedState(const ui::Event& event) override; std::unique_ptr<views::InkDrop> CreateInkDrop() override; std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override; + void PaintButtonContents(gfx::Canvas* canvas) override; private: // Get the center point of the app list button used to draw its background and
diff --git a/ash/shelf/overflow_bubble_view.cc b/ash/shelf/overflow_bubble_view.cc index 22af1f0..de12a49 100644 --- a/ash/shelf/overflow_bubble_view.cc +++ b/ash/shelf/overflow_bubble_view.cc
@@ -11,7 +11,6 @@ #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_constants.h" #include "ash/shell.h" -#include "ash/wm_window.h" #include "base/i18n/rtl.h" #include "ui/display/display.h" #include "ui/display/screen.h" @@ -163,8 +162,7 @@ views::Widget::InitParams* params, views::Widget* bubble_widget) const { // Place the bubble in the same root window as the anchor. - WmWindow::Get(anchor_widget()->GetNativeWindow()) - ->GetRootWindowController() + RootWindowController::ForWindow(anchor_widget()->GetNativeWindow()) ->ConfigureWidgetInitParamsForContainer( bubble_widget, kShellWindowId_ShelfBubbleContainer, params); }
diff --git a/ash/shelf/overflow_button.cc b/ash/shelf/overflow_button.cc index 0b96ec9..5941924 100644 --- a/ash/shelf/overflow_button.cc +++ b/ash/shelf/overflow_button.cc
@@ -109,12 +109,6 @@ SchedulePaint(); } -void OverflowButton::OnPaint(gfx::Canvas* canvas) { - gfx::Rect bounds = CalculateButtonBounds(); - PaintBackground(canvas, bounds); - PaintForeground(canvas, bounds); -} - std::unique_ptr<views::InkDrop> OverflowButton::CreateInkDrop() { std::unique_ptr<views::InkDropImpl> ink_drop = CreateDefaultFloodFillInkDropImpl(); @@ -149,6 +143,12 @@ size(), insets, kOverflowButtonCornerRadius); } +void OverflowButton::PaintButtonContents(gfx::Canvas* canvas) { + gfx::Rect bounds = CalculateButtonBounds(); + PaintBackground(canvas, bounds); + PaintForeground(canvas, bounds); +} + void OverflowButton::PaintBackground(gfx::Canvas* canvas, const gfx::Rect& bounds) { cc::PaintFlags flags;
diff --git a/ash/shelf/overflow_button.h b/ash/shelf/overflow_button.h index 88bb6d2..a189406 100644 --- a/ash/shelf/overflow_button.h +++ b/ash/shelf/overflow_button.h
@@ -46,12 +46,12 @@ void UpdateChevronImage(); // views::CustomButton: - void OnPaint(gfx::Canvas* canvas) override; std::unique_ptr<views::InkDrop> CreateInkDrop() override; std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; bool ShouldEnterPushedState(const ui::Event& event) override; void NotifyClick(const ui::Event& event) override; std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override; + void PaintButtonContents(gfx::Canvas* canvas) override; // Helper functions to paint the background and foreground of the button // at |bounds|.
diff --git a/ash/shelf/shelf.cc b/ash/shelf/shelf.cc index 3119297..dce85c9 100644 --- a/ash/shelf/shelf.cc +++ b/ash/shelf/shelf.cc
@@ -16,7 +16,6 @@ #include "ash/shelf/shelf_observer.h" #include "ash/shelf/shelf_widget.h" #include "ash/shell.h" -#include "ash/wm_window.h" #include "base/logging.h" #include "base/memory/ptr_util.h" #include "ui/display/types/display_constants.h"
diff --git a/ash/shelf/shelf_button.cc b/ash/shelf/shelf_button.cc index 53cf800..0fc01bf 100644 --- a/ash/shelf/shelf_button.cc +++ b/ash/shelf/shelf_button.cc
@@ -11,6 +11,7 @@ #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_constants.h" #include "ash/shelf/shelf_view.h" +#include "ash/system/tray/tray_popup_utils.h" #include "base/memory/ptr_util.h" #include "base/time/time.h" #include "skia/ext/image_operations.h" @@ -26,6 +27,7 @@ #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/square_ink_drop_ripple.h" #include "ui/views/controls/image_view.h" +#include "ui/views/painter.h" namespace { @@ -233,6 +235,8 @@ AddChildView(indicator_); AddChildView(icon_view_); + + SetFocusPainter(TrayPopupUtils::CreateFocusPainter()); } ShelfButton::~ShelfButton() { @@ -432,14 +436,6 @@ CustomButton::OnBlur(); } -void ShelfButton::OnPaint(gfx::Canvas* canvas) { - CustomButton::OnPaint(canvas); - if (HasFocus()) { - canvas->DrawSolidFocusRect(gfx::RectF(GetLocalBounds()), kFocusBorderColor, - kFocusBorderThickness); - } -} - void ShelfButton::OnGestureEvent(ui::GestureEvent* event) { switch (event->type()) { case ui::ET_GESTURE_TAP_DOWN:
diff --git a/ash/shelf/shelf_button.h b/ash/shelf/shelf_button.h index 540d20ac..7d254c8 100644 --- a/ash/shelf/shelf_button.h +++ b/ash/shelf/shelf_button.h
@@ -79,7 +79,6 @@ void ChildPreferredSizeChanged(views::View* child) override; void OnFocus() override; void OnBlur() override; - void OnPaint(gfx::Canvas* canvas) override; // ui::EventHandler overrides: void OnGestureEvent(ui::GestureEvent* event) override;
diff --git a/ash/shelf/shelf_controller.cc b/ash/shelf/shelf_controller.cc index 2bc855b..fda0675 100644 --- a/ash/shelf/shelf_controller.cc +++ b/ash/shelf/shelf_controller.cc
@@ -10,7 +10,6 @@ #include "ash/shelf/app_list_shelf_item_delegate.h" #include "ash/shelf/shelf.h" #include "ash/shell.h" -#include "ash/wm_window.h" #include "base/strings/utf_string_conversions.h" #include "ui/base/models/simple_menu_model.h" #include "ui/display/display.h"
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc index b8c65bc..62a52fa 100644 --- a/ash/shelf/shelf_view.cc +++ b/ash/shelf/shelf_view.cc
@@ -27,7 +27,6 @@ #include "ash/shell_port.h" #include "ash/strings/grit/ash_strings.h" #include "ash/wm/root_window_finder.h" -#include "ash/wm_window.h" #include "base/auto_reset.h" #include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" @@ -1040,10 +1039,9 @@ DCHECK_NE(-1, current_index); std::string dragged_app_id = model_->items()[current_index].id.app_id; - gfx::Point screen_location = - WmWindow::Get(GetWidget()->GetNativeWindow()) - ->GetRootWindow() - ->ConvertPointToScreen(event.root_location()); + gfx::Point screen_location = event.root_location(); + ::wm::ConvertPointToScreen(GetWidget()->GetNativeWindow()->GetRootWindow(), + &screen_location); // To avoid ugly forwards and backwards flipping we use different constants // for ripping off / re-inserting the items.
diff --git a/ash/shelf/shelf_widget_unittest.cc b/ash/shelf/shelf_widget_unittest.cc index e55d689..0b81b03 100644 --- a/ash/shelf/shelf_widget_unittest.cc +++ b/ash/shelf/shelf_widget_unittest.cc
@@ -17,7 +17,6 @@ #include "ash/test/shelf_view_test_api.h" #include "ash/test/test_shell_delegate.h" #include "ash/wm/window_util.h" -#include "ash/wm_window.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/display/display.h" #include "ui/events/event_utils.h"
diff --git a/ash/shelf/shelf_window_watcher.cc b/ash/shelf/shelf_window_watcher.cc index c1112f4..f5efa167 100644 --- a/ash/shelf/shelf_window_watcher.cc +++ b/ash/shelf/shelf_window_watcher.cc
@@ -17,7 +17,6 @@ #include "ash/shell_port.h" #include "ash/wm/window_state.h" #include "ash/wm/window_util.h" -#include "ash/wm_window.h" #include "base/strings/string_number_conversions.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h"
diff --git a/ash/shelf/shelf_window_watcher_unittest.cc b/ash/shelf/shelf_window_watcher_unittest.cc index 0b303c57..1da5df1 100644 --- a/ash/shelf/shelf_window_watcher_unittest.cc +++ b/ash/shelf/shelf_window_watcher_unittest.cc
@@ -16,7 +16,6 @@ #include "ash/test/ash_test_base.h" #include "ash/wm/window_resizer.h" #include "ash/wm/window_state.h" -#include "ash/wm_window.h" #include "base/strings/string_number_conversions.h" #include "ui/aura/window.h" #include "ui/base/hit_test.h"
diff --git a/ash/system/bluetooth/tray_bluetooth.cc b/ash/system/bluetooth/tray_bluetooth.cc index 58cd1aa..ffc8b2642 100644 --- a/ash/system/bluetooth/tray_bluetooth.cc +++ b/ash/system/bluetooth/tray_bluetooth.cc
@@ -310,8 +310,8 @@ // Show user Bluetooth state if there is no bluetooth devices in list. if (device_map_.size() == 0 && bluetooth_available && bluetooth_enabled) { - scroll_content()->AddChildView(TrayPopupUtils::CreateInfoLabelRowView( - IDS_ASH_STATUS_TRAY_BLUETOOTH_DISCOVERING)); + scroll_content()->AddChildView( + new InfoLabel(IDS_ASH_STATUS_TRAY_BLUETOOTH_DISCOVERING)); } // Focus the device which was focused before the device-list update.
diff --git a/ash/system/network/network_list.cc b/ash/system/network/network_list.cc index b462bbd..21ee550 100644 --- a/ash/system/network/network_list.cc +++ b/ash/system/network/network_list.cc
@@ -669,30 +669,22 @@ void NetworkListView::UpdateInfoLabel(int message_id, int insertion_index, - views::Label** label_ptr) { - views::Label* label = *label_ptr; + InfoLabel** info_label_ptr) { + InfoLabel* info_label = *info_label_ptr; if (!message_id) { - if (label) { + if (info_label) { needs_relayout_ = true; - delete label; - *label_ptr = nullptr; + delete info_label; + *info_label_ptr = nullptr; } return; } - base::string16 text = l10n_util::GetStringUTF16(message_id); - if (!label) { - // TODO(mohsen): Update info label to follow MD specs. See - // https://crbug.com/687778. - label = new views::Label(); - label->SetBorder(views::CreateEmptyBorder( - kTrayPopupPaddingBetweenItems, kTrayPopupPaddingHorizontal, - kTrayPopupPaddingBetweenItems, 0)); - label->SetHorizontalAlignment(gfx::ALIGN_LEFT); - label->SetEnabledColor(SkColorSetARGB(192, 0, 0, 0)); - } - label->SetText(text); - PlaceViewAtIndex(label, insertion_index); - *label_ptr = label; + if (!info_label) + info_label = new InfoLabel(message_id); + else + info_label->SetMessage(message_id); + PlaceViewAtIndex(info_label, insertion_index); + *info_label_ptr = info_label; } int NetworkListView::UpdateSectionHeaderRow(NetworkTypePattern pattern,
diff --git a/ash/system/network/network_list.h b/ash/system/network/network_list.h index 98436f3..1de25cd 100644 --- a/ash/system/network/network_list.h +++ b/ash/system/network/network_list.h
@@ -19,7 +19,6 @@ #include "chromeos/network/network_type_pattern.h" namespace views { -class Label; class Separator; class View; } @@ -88,23 +87,24 @@ int child_index); void UpdateNetworkChild(int index, const NetworkInfo* info); - // Reorders children of |container()| as necessary placing |view| at |index|. + // Reorders children of |scroll_content()| as necessary placing |view| at + // |index|. void PlaceViewAtIndex(views::View* view, int index); - // Creates a Label with text specified by |message_id| and adds it to - // |container()| if necessary or updates the text and reorders the - // |container()| placing the label at |insertion_index|. When |message_id| is - // zero removes the |*label_ptr| from the |container()| and destroys it. - // |label_ptr| is an in / out parameter and is only modified if the Label is - // created or destroyed. + // Creates an info label with text specified by |message_id| and adds it to + // |scroll_content()| if necessary or updates the text and reorders the + // |scroll_content()| placing the info label at |insertion_index|. When + // |message_id| is zero removes the |*info_label_ptr| from the + // |scroll_content()| and destroys it. |info_label_ptr| is an in/out parameter + // and is only modified if the info label is created or destroyed. void UpdateInfoLabel(int message_id, int insertion_index, - views::Label** label_ptr); + InfoLabel** info_label_ptr); - // Creates a cellular/Wi-Fi header row |view| and adds it to |container()| if - // necessary and reorders the |container()| placing the |view| at - // |child_index|. Returns the index where the next child should be inserted, - // i.e., the index directly after the last inserted child. + // Creates a cellular/tether/Wi-Fi header row |view| and adds it to + // |scroll_content()| if necessary and reorders the |scroll_content()| placing + // the |view| at |child_index|. Returns the index where the next child should + // be inserted, i.e., the index directly after the last inserted child. int UpdateSectionHeaderRow(chromeos::NetworkTypePattern pattern, bool enabled, int child_index, @@ -120,8 +120,8 @@ bool needs_relayout_; - views::Label* no_wifi_networks_view_; - views::Label* no_cellular_networks_view_; + InfoLabel* no_wifi_networks_view_; + InfoLabel* no_cellular_networks_view_; SectionHeaderRowView* cellular_header_view_; SectionHeaderRowView* tether_header_view_; SectionHeaderRowView* wifi_header_view_;
diff --git a/ash/system/tray/actionable_view.cc b/ash/system/tray/actionable_view.cc index ccb3d86..d169f9a8 100644 --- a/ash/system/tray/actionable_view.cc +++ b/ash/system/tray/actionable_view.cc
@@ -17,6 +17,7 @@ #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_mask.h" +#include "ui/views/painter.h" namespace ash { @@ -34,6 +35,7 @@ set_ink_drop_visible_opacity(kTrayPopupInkDropRippleOpacity); set_has_ink_drop_action_on_click(false); set_notify_enter_exit_on_child(true); + SetFocusPainter(TrayPopupUtils::CreateFocusPainter()); } ActionableView::~ActionableView() { @@ -41,11 +43,6 @@ *destroyed_ = true; } -void ActionableView::OnPaintFocus(gfx::Canvas* canvas) { - gfx::RectF rect(GetLocalBounds()); - canvas->DrawSolidFocusRect(rect, kFocusBorderColor, kFocusBorderThickness); -} - void ActionableView::HandlePerformActionResult(bool action_performed, const ui::Event& event) { AnimateInkDrop(action_performed ? views::InkDropState::ACTION_TRIGGERED @@ -74,24 +71,6 @@ node_data->SetName(accessible_name_); } -void ActionableView::OnPaint(gfx::Canvas* canvas) { - CustomButton::OnPaint(canvas); - if (HasFocus()) - OnPaintFocus(canvas); -} - -void ActionableView::OnFocus() { - CustomButton::OnFocus(); - // We render differently when focused. - SchedulePaint(); -} - -void ActionableView::OnBlur() { - CustomButton::OnBlur(); - // We render differently when focused. - SchedulePaint(); -} - std::unique_ptr<views::InkDrop> ActionableView::CreateInkDrop() { return TrayPopupUtils::CreateInkDrop(ink_drop_style_, this); }
diff --git a/ash/system/tray/actionable_view.h b/ash/system/tray/actionable_view.h index 95d43b4..7e21efd 100644 --- a/ash/system/tray/actionable_view.h +++ b/ash/system/tray/actionable_view.h
@@ -43,11 +43,6 @@ protected: SystemTrayItem* owner() { return owner_; } - // Draws focus rectangle on the canvas. - // Default implementation draws the focus rectangle with certain inset and - // color. Subclasses can override to change the default settings. - virtual void OnPaintFocus(gfx::Canvas* canvas); - // Performs an action when user clicks on the view (on mouse-press event), or // presses a key when this view is in focus. Returns true if the event has // been handled and an action was performed. Returns false otherwise. @@ -65,9 +60,6 @@ const char* GetClassName() const override; bool OnKeyPressed(const ui::KeyEvent& event) override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override; - void OnPaint(gfx::Canvas* canvas) override; - void OnFocus() override; - void OnBlur() override; std::unique_ptr<views::InkDrop> CreateInkDrop() override; std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
diff --git a/ash/system/tray/system_menu_button.cc b/ash/system/tray/system_menu_button.cc index f5e6fd3..b0a913b 100644 --- a/ash/system/tray/system_menu_button.cc +++ b/ash/system/tray/system_menu_button.cc
@@ -36,7 +36,6 @@ SetTooltipText(l10n_util::GetStringUTF16(accessible_name_id)); - SetFocusPainter(TrayPopupUtils::CreateFocusPainter()); TrayPopupUtils::ConfigureTrayPopupButton(this); }
diff --git a/ash/system/tray/tray_background_view.cc b/ash/system/tray/tray_background_view.cc index c16c335..d360779 100644 --- a/ash/system/tray/tray_background_view.cc +++ b/ash/system/tray/tray_background_view.cc
@@ -31,6 +31,7 @@ #include "ui/views/animation/ink_drop_mask.h" #include "ui/views/background.h" #include "ui/views/layout/fill_layout.h" +#include "ui/views/painter.h" #include "ui/wm/core/window_animations.h" namespace { @@ -277,8 +278,44 @@ return highlight; } +void TrayBackgroundView::PaintButtonContents(gfx::Canvas* canvas) { + if (shelf()->GetBackgroundType() == + ShelfBackgroundType::SHELF_BACKGROUND_DEFAULT || + !separator_visible_) { + return; + } + // In the given |canvas|, for a horizontal shelf draw a separator line to the + // right or left of the TrayBackgroundView when the system is LTR or RTL + // aligned, respectively. For a vertical shelf draw the separator line + // underneath the items instead. + const gfx::Rect local_bounds = GetLocalBounds(); + const SkColor color = SkColorSetA(SK_ColorWHITE, 0x4D); + + if (shelf_->IsHorizontalAlignment()) { + const gfx::PointF point( + base::i18n::IsRTL() ? 0 : (local_bounds.width() - kSeparatorWidth), + (kShelfSize - kTrayItemSize) / 2); + const gfx::Vector2dF vector(0, kTrayItemSize); + canvas->Draw1pxLine(point, point + vector, color); + } else { + const gfx::PointF point((kShelfSize - kTrayItemSize) / 2, + local_bounds.height() - kSeparatorWidth); + const gfx::Vector2dF vector(kTrayItemSize, 0); + canvas->Draw1pxLine(point, point + vector, color); + } +} + void TrayBackgroundView::UpdateAfterShelfAlignmentChange() { tray_container_->UpdateAfterShelfAlignmentChange(); + + // The tray itself expands to the right and bottom edge of the screen to make + // sure clicking on the edges brings up the popup. However, the focus border + // should be only around the container. + gfx::Rect paint_bounds(GetBackgroundBounds()); + paint_bounds.Inset(gfx::Insets(-kFocusBorderThickness)); + SetFocusPainter(views::Painter::CreateSolidFocusPainter( + kFocusBorderColor, kFocusBorderThickness, + GetLocalBounds().InsetsFrom(paint_bounds))); } void TrayBackgroundView::OnImplicitAnimationsCompleted() { @@ -385,44 +422,6 @@ ActionableView::HandlePerformActionResult(action_performed, event); } -void TrayBackgroundView::OnPaintFocus(gfx::Canvas* canvas) { - // The tray itself expands to the right and bottom edge of the screen to make - // sure clicking on the edges brings up the popup. However, the focus border - // should be only around the container. - gfx::RectF paint_bounds(GetBackgroundBounds()); - paint_bounds.Inset(gfx::Insets(-kFocusBorderThickness)); - canvas->DrawSolidFocusRect(paint_bounds, kFocusBorderColor, - kFocusBorderThickness); -} - -void TrayBackgroundView::OnPaint(gfx::Canvas* canvas) { - ActionableView::OnPaint(canvas); - if (shelf()->GetBackgroundType() == - ShelfBackgroundType::SHELF_BACKGROUND_DEFAULT || - !separator_visible_) { - return; - } - // In the given |canvas|, for a horizontal shelf draw a separator line to the - // right or left of the TrayBackgroundView when the system is LTR or RTL - // aligned, respectively. For a vertical shelf draw the separator line - // underneath the items instead. - const gfx::Rect local_bounds = GetLocalBounds(); - const SkColor color = SkColorSetA(SK_ColorWHITE, 0x4D); - - if (shelf_->IsHorizontalAlignment()) { - const gfx::PointF point( - base::i18n::IsRTL() ? 0 : (local_bounds.width() - kSeparatorWidth), - (kShelfSize - kTrayItemSize) / 2); - const gfx::Vector2dF vector(0, kTrayItemSize); - canvas->Draw1pxLine(point, point + vector, color); - } else { - const gfx::PointF point((kShelfSize - kTrayItemSize) / 2, - local_bounds.height() - kSeparatorWidth); - const gfx::Vector2dF vector(kTrayItemSize, 0); - canvas->Draw1pxLine(point, point + vector, color); - } -} - gfx::Insets TrayBackgroundView::GetBackgroundInsets() const { gfx::Insets insets = GetMirroredBackgroundInsets(shelf_->IsHorizontalAlignment());
diff --git a/ash/system/tray/tray_background_view.h b/ash/system/tray/tray_background_view.h index 8a3b1f3..0429417 100644 --- a/ash/system/tray/tray_background_view.h +++ b/ash/system/tray/tray_background_view.h
@@ -46,12 +46,12 @@ void ChildPreferredSizeChanged(views::View* child) override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override; void AboutToRequestFocusFromTabTraversal(bool reverse) override; - void OnPaint(gfx::Canvas* canvas) override; // ActionableView: std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight() const override; + void PaintButtonContents(gfx::Canvas* canvas) override; // Called whenever the shelf alignment changes. virtual void UpdateAfterShelfAlignmentChange(); @@ -109,7 +109,6 @@ bool PerformAction(const ui::Event& event) override; void HandlePerformActionResult(bool action_performed, const ui::Event& event) override; - void OnPaintFocus(gfx::Canvas* canvas) override; private: class TrayWidgetObserver;
diff --git a/ash/system/tray/tray_details_view.cc b/ash/system/tray/tray_details_view.cc index f334fc5..4aaf772 100644 --- a/ash/system/tray/tray_details_view.cc +++ b/ash/system/tray/tray_details_view.cc
@@ -35,6 +35,7 @@ #include "ui/views/controls/scroll_view.h" #include "ui/views/controls/separator.h" #include "ui/views/layout/box_layout.h" +#include "ui/views/layout/fill_layout.h" #include "ui/views/view_targeter.h" #include "ui/views/view_targeter_delegate.h" @@ -236,6 +237,39 @@ } // namespace +//////////////////////////////////////////////////////////////////////////////// +// TrayDetailsView::InfoLabel: + +TrayDetailsView::InfoLabel::InfoLabel(int message_id) + : label_(TrayPopupUtils::CreateDefaultLabel()) { + SetLayoutManager(new views::FillLayout); + + TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::SYSTEM_INFO); + style.SetupLabel(label_); + + TriView* tri_view = TrayPopupUtils::CreateMultiTargetRowView(); + tri_view->SetInsets(gfx::Insets(0, + kMenuExtraMarginFromLeftEdge + + kTrayPopupPaddingHorizontal - + kTrayPopupLabelHorizontalPadding, + 0, kTrayPopupPaddingHorizontal)); + tri_view->SetContainerVisible(TriView::Container::START, false); + tri_view->SetContainerVisible(TriView::Container::END, false); + tri_view->AddView(TriView::Container::CENTER, label_); + AddChildView(tri_view); + + SetMessage(message_id); +} + +TrayDetailsView::InfoLabel::~InfoLabel() {} + +void TrayDetailsView::InfoLabel::SetMessage(int message_id) { + label_->SetText(l10n_util::GetStringUTF16(message_id)); +} + +//////////////////////////////////////////////////////////////////////////////// +// TrayDetailsView: + TrayDetailsView::TrayDetailsView(SystemTrayItem* owner) : owner_(owner), box_layout_(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)),
diff --git a/ash/system/tray/tray_details_view.h b/ash/system/tray/tray_details_view.h index 3761ba7..f046fcdc 100644 --- a/ash/system/tray/tray_details_view.h +++ b/ash/system/tray/tray_details_view.h
@@ -22,6 +22,7 @@ namespace views { class BoxLayout; class CustomButton; +class Label; class ProgressBar; class ScrollView; } // namespace views @@ -54,6 +55,22 @@ SystemTrayItem* owner() { return owner_; } protected: + // A view containing only a label, which is to be inserted as a non-targetable + // row within a system menu detailed view (e.g., the "Scanning for devices..." + // message that can appear at the top of the Bluetooth detailed view). + class InfoLabel : public View { + public: + explicit InfoLabel(int message_id); + ~InfoLabel() override; + + void SetMessage(int message_id); + + private: + views::Label* const label_; + + DISALLOW_COPY_AND_ASSIGN(InfoLabel); + }; + // views::View: void Layout() override; int GetHeightForWidth(int width) const override;
diff --git a/ash/system/tray/tray_popup_utils.cc b/ash/system/tray/tray_popup_utils.cc index 08bf25c..820647d 100644 --- a/ash/system/tray/tray_popup_utils.cc +++ b/ash/system/tray/tray_popup_utils.cc
@@ -185,23 +185,6 @@ return tri_view; } -views::View* TrayPopupUtils::CreateInfoLabelRowView(int message_id) { - views::Label* label = TrayPopupUtils::CreateDefaultLabel(); - label->SetText(l10n_util::GetStringUTF16(message_id)); - TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::SYSTEM_INFO); - style.SetupLabel(label); - - TriView* tri_view = CreateMultiTargetRowView(); - tri_view->SetInsets( - gfx::Insets(0, kMenuExtraMarginFromLeftEdge + kTrayPopupPaddingHorizontal, - 0, kTrayPopupPaddingHorizontal)); - tri_view->SetContainerVisible(TriView::Container::START, false); - tri_view->SetContainerVisible(TriView::Container::END, false); - tri_view->AddView(TriView::Container::CENTER, label); - - return tri_view; -} - TriView* TrayPopupUtils::CreateMultiTargetRowView() { TriView* tri_view = new TriView(0 /* padding_between_items */); @@ -275,10 +258,7 @@ } void TrayPopupUtils::ConfigureTrayPopupButton(views::CustomButton* button) { - // All buttons that call into here want this focus painter, but - // SetFocusPainter is defined separately on derived classes and isn't part of - // CustomButton. TODO(estade): Address this. - // button->SetFocusPainter(TrayPopupUtils::CreateFocusPainter()); + button->SetFocusPainter(TrayPopupUtils::CreateFocusPainter()); button->SetFocusForPlatform(); button->SetInkDropMode(views::InkDropHostView::InkDropMode::ON);
diff --git a/ash/system/tray/tray_popup_utils.h b/ash/system/tray/tray_popup_utils.h index db268693..e42ff8d9 100644 --- a/ash/system/tray/tray_popup_utils.h +++ b/ash/system/tray/tray_popup_utils.h
@@ -67,13 +67,6 @@ // once network and VPN alse use TrayDetailsView::AddScrollListSubHeader(). static TriView* CreateSubHeaderRowView(bool start_visible); - // Creates a view containing only a label (corresponding to |message_id|), - // which is to be inserted as a non-targetable row within a system menu - // detailed view (e.g., the "Scanning for devices..." message that can appear - // at the top of the Bluetooth detailed view). The caller takes over ownership - // of the created view. - static views::View* CreateInfoLabelRowView(int message_id); - // Creates a container view to be used by system menu rows that want to embed // a targetable area within one (or more) of the containers OR by any row // that requires a non-default layout within the container views. The returned
diff --git a/ash/system/user/button_from_view.cc b/ash/system/user/button_from_view.cc index 0772fc2..3218703 100644 --- a/ash/system/user/button_from_view.cc +++ b/ash/system/user/button_from_view.cc
@@ -12,13 +12,13 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "ui/accessibility/ax_node_data.h" -#include "ui/gfx/canvas.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" #include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_mask.h" #include "ui/views/layout/fill_layout.h" +#include "ui/views/painter.h" namespace ash { namespace tray { @@ -41,6 +41,8 @@ // Only make it focusable when we are active/interested in clicks. if (listener) SetFocusForPlatform(); + + SetFocusPainter(TrayPopupUtils::CreateFocusPainter()); } ButtonFromView::~ButtonFromView() {} @@ -53,26 +55,6 @@ button_hovered_ = false; } -void ButtonFromView::OnPaint(gfx::Canvas* canvas) { - View::OnPaint(canvas); - if (HasFocus()) { - gfx::RectF rect(GetLocalBounds()); - canvas->DrawSolidFocusRect(rect, kFocusBorderColor, kFocusBorderThickness); - } -} - -void ButtonFromView::OnFocus() { - View::OnFocus(); - // Adding focus frame. - SchedulePaint(); -} - -void ButtonFromView::OnBlur() { - View::OnBlur(); - // Removing focus frame. - SchedulePaint(); -} - void ButtonFromView::GetAccessibleNodeData(ui::AXNodeData* node_data) { views::CustomButton::GetAccessibleNodeData(node_data); // If no label has been explicitly set via CustomButton::SetAccessibleName(),
diff --git a/ash/system/user/button_from_view.h b/ash/system/user/button_from_view.h index d50f10e0..f57f978f 100644 --- a/ash/system/user/button_from_view.h +++ b/ash/system/user/button_from_view.h
@@ -32,9 +32,6 @@ // views::View: void OnMouseEntered(const ui::MouseEvent& event) override; void OnMouseExited(const ui::MouseEvent& event) override; - void OnPaint(gfx::Canvas* canvas) override; - void OnFocus() override; - void OnBlur() override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override; void Layout() override;
diff --git a/base/sequence_checker_impl.cc b/base/sequence_checker_impl.cc index 6a9b5b2..bea3e77 100644 --- a/base/sequence_checker_impl.cc +++ b/base/sequence_checker_impl.cc
@@ -19,7 +19,7 @@ sequenced_worker_pool_token_( SequencedWorkerPool::GetSequenceTokenForCurrentThread()) { // SequencedWorkerPool doesn't use SequenceToken and code outside of - // SequenceWorkerPool doesn't set a SequencedWorkerPool token. + // SequencedWorkerPool doesn't set a SequencedWorkerPool token. DCHECK(!sequence_token_.IsValid() || !sequenced_worker_pool_token_.IsValid()); }
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc index e0605290..57cb1b4 100644 --- a/cc/layers/layer_impl.cc +++ b/cc/layers/layer_impl.cc
@@ -771,7 +771,8 @@ } void LayerImpl::SetNeedsPushProperties() { - if (layer_tree_impl_ && !needs_push_properties_) { + // There's no need to push layer properties on the active tree. + if (!needs_push_properties_ && !layer_tree_impl()->IsActiveTree()) { needs_push_properties_ = true; layer_tree_impl()->AddLayerShouldPushProperties(this); }
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h index 10474cf..35a155de 100644 --- a/cc/layers/layer_impl.h +++ b/cc/layers/layer_impl.h
@@ -287,6 +287,9 @@ ViewportLayerType viewport_layer_type() const { return static_cast<ViewportLayerType>(viewport_layer_type_); } + bool is_viewport_layer_type() const { + return viewport_layer_type() != NOT_VIEWPORT_LAYER; + } void SetCurrentScrollOffset(const gfx::ScrollOffset& scroll_offset); gfx::ScrollOffset CurrentScrollOffset() const;
diff --git a/cc/layers/layer_impl_unittest.cc b/cc/layers/layer_impl_unittest.cc index 07259ad1..d2744ee 100644 --- a/cc/layers/layer_impl_unittest.cc +++ b/cc/layers/layer_impl_unittest.cc
@@ -115,9 +115,9 @@ return gfx::Vector2dF(delta.x(), delta.y()); } -TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) { +TEST(LayerImplTest, VerifyPendingLayerChangesAreTrackedProperly) { // - // This test checks that layerPropertyChanged() has the correct behavior. + // This test checks that LayerPropertyChanged() has the correct behavior. // // The constructor on this will fake that we are on the correct thread. @@ -129,33 +129,28 @@ FakeLayerTreeHostImpl host_impl(&task_runner_provider, &task_graph_runner); host_impl.SetVisible(true); EXPECT_TRUE(host_impl.InitializeRenderer(compositor_frame_sink.get())); + host_impl.CreatePendingTree(); std::unique_ptr<LayerImpl> root_clip_ptr = - LayerImpl::Create(host_impl.active_tree(), 1); + LayerImpl::Create(host_impl.pending_tree(), 1); LayerImpl* root_clip = root_clip_ptr.get(); std::unique_ptr<LayerImpl> root_ptr = - LayerImpl::Create(host_impl.active_tree(), 2); + LayerImpl::Create(host_impl.pending_tree(), 2); LayerImpl* root = root_ptr.get(); root_clip_ptr->test_properties()->AddChild(std::move(root_ptr)); - host_impl.active_tree()->SetRootLayerForTesting(std::move(root_clip_ptr)); - - // Make root the inner viewport scroll layer. This ensures the later call to - // |SetViewportBoundsDelta| will be on a viewport layer. - LayerTreeImpl::ViewportLayerIds viewport_ids; - viewport_ids.inner_viewport_scroll = root->id(); - host_impl.active_tree()->SetViewportLayersFromIds(viewport_ids); + host_impl.pending_tree()->SetRootLayerForTesting(std::move(root_clip_ptr)); root->test_properties()->force_render_surface = true; root->SetMasksToBounds(true); root->layer_tree_impl()->ResetAllChangeTracking(); root->test_properties()->AddChild( - LayerImpl::Create(host_impl.active_tree(), 7)); + LayerImpl::Create(host_impl.pending_tree(), 7)); LayerImpl* child = root->test_properties()->children[0]; child->test_properties()->AddChild( - LayerImpl::Create(host_impl.active_tree(), 8)); + LayerImpl::Create(host_impl.pending_tree(), 8)); LayerImpl* grand_child = child->test_properties()->children[0]; root->SetScrollClipLayer(root_clip->id()); - host_impl.active_tree()->BuildLayerListAndPropertyTreesForTesting(); + host_impl.pending_tree()->BuildLayerListAndPropertyTreesForTesting(); // Adding children is an internal operation and should not mark layers as // changed. @@ -167,7 +162,7 @@ float arbitrary_number = 0.352f; gfx::Size arbitrary_size = gfx::Size(111, 222); gfx::Point arbitrary_point = gfx::Point(333, 444); - gfx::Vector2d arbitrary_vector2d = gfx::Vector2d(111, 222); + gfx::Rect arbitrary_rect = gfx::Rect(arbitrary_point, arbitrary_size); SkColor arbitrary_color = SkColorSetRGB(10, 20, 30); gfx::Transform arbitrary_transform; @@ -180,49 +175,28 @@ EXECUTE_AND_VERIFY_NEEDS_PUSH_PROPERTIES_AND_SUBTREE_DID_NOT_CHANGE( root->SetUpdateRect(arbitrary_rect)); EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->SetBounds(arbitrary_size)); - host_impl.active_tree()->property_trees()->needs_rebuild = true; - host_impl.active_tree()->BuildLayerListAndPropertyTreesForTesting(); + host_impl.pending_tree()->property_trees()->needs_rebuild = true; + host_impl.pending_tree()->BuildLayerListAndPropertyTreesForTesting(); // Changing these properties affects the entire subtree of layers. EXECUTE_AND_VERIFY_NO_NEED_TO_PUSH_PROPERTIES_AND_SUBTREE_CHANGED( - host_impl.active_tree()->SetFilterMutated(root->element_id(), - arbitrary_filters)); + host_impl.pending_tree()->SetFilterMutated(root->element_id(), + arbitrary_filters)); EXECUTE_AND_VERIFY_NO_NEED_TO_PUSH_PROPERTIES_AND_SUBTREE_CHANGED( - host_impl.active_tree()->SetFilterMutated(root->element_id(), - FilterOperations())); + host_impl.pending_tree()->SetFilterMutated(root->element_id(), + FilterOperations())); EXECUTE_AND_VERIFY_NO_NEED_TO_PUSH_PROPERTIES_AND_SUBTREE_CHANGED( - host_impl.active_tree()->SetOpacityMutated(root->element_id(), - arbitrary_number)); + host_impl.pending_tree()->SetOpacityMutated(root->element_id(), + arbitrary_number)); EXECUTE_AND_VERIFY_NO_NEED_TO_PUSH_PROPERTIES_AND_SUBTREE_CHANGED( - host_impl.active_tree()->SetTransformMutated(root->element_id(), - arbitrary_transform)); - EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->ScrollBy(arbitrary_vector2d); - root->SetNeedsPushProperties()); - // SetViewportBoundsDelta changes subtree only when masks_to_bounds is true - // and it doesn't set needs_push_properties as it is always called on active - // tree. - root->SetMasksToBounds(true); - EXECUTE_AND_VERIFY_SUBTREE_CHANGED( - root->SetViewportBoundsDelta(arbitrary_vector2d); - root->SetNeedsPushProperties()); + host_impl.pending_tree()->SetTransformMutated(root->element_id(), + arbitrary_transform)); // Changing these properties only affects the layer itself. EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->SetDrawsContent(true)); EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED( root->SetBackgroundColor(arbitrary_color)); - // Special case: check that SetBounds changes behavior depending on - // masksToBounds. - gfx::Size bounds_size(135, 246); - root->SetMasksToBounds(false); - EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->SetBounds(bounds_size)); - host_impl.active_tree()->property_trees()->needs_rebuild = true; - host_impl.active_tree()->BuildLayerListAndPropertyTreesForTesting(); - - root->SetMasksToBounds(true); - host_impl.active_tree()->property_trees()->needs_rebuild = true; - host_impl.active_tree()->BuildLayerListAndPropertyTreesForTesting(); - // Changing these properties does not cause the layer to be marked as changed // but does cause the layer to need to push properties. EXECUTE_AND_VERIFY_NEEDS_PUSH_PROPERTIES_AND_SUBTREE_DID_NOT_CHANGE( @@ -238,7 +212,82 @@ root->SetPosition(arbitrary_point_f)); EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->SetContentsOpaque(true)); EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->SetDrawsContent(true)); - EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->SetBounds(bounds_size)); + EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->SetBounds(root->bounds())); +} + +TEST(LayerImplTest, VerifyActiveLayerChangesAreTrackedProperly) { + FakeImplTaskRunnerProvider task_runner_provider; + TestTaskGraphRunner task_graph_runner; + std::unique_ptr<CompositorFrameSink> compositor_frame_sink = + FakeCompositorFrameSink::Create3d(); + FakeLayerTreeHostImpl host_impl(&task_runner_provider, &task_graph_runner); + host_impl.SetVisible(true); + EXPECT_TRUE(host_impl.InitializeRenderer(compositor_frame_sink.get())); + std::unique_ptr<LayerImpl> root_clip_ptr = + LayerImpl::Create(host_impl.active_tree(), 1); + LayerImpl* root_clip = root_clip_ptr.get(); + std::unique_ptr<LayerImpl> root_ptr = + LayerImpl::Create(host_impl.active_tree(), 2); + LayerImpl* root = root_ptr.get(); + root_clip_ptr->test_properties()->AddChild(std::move(root_ptr)); + host_impl.active_tree()->SetRootLayerForTesting(std::move(root_clip_ptr)); + + root->test_properties()->AddChild( + LayerImpl::Create(host_impl.active_tree(), 7)); + LayerImpl* child = root->test_properties()->children[0]; + root->SetScrollClipLayer(root_clip->id()); + host_impl.active_tree()->BuildLayerListAndPropertyTreesForTesting(); + + // Make root the inner viewport container layer. This ensures the later call + // to |SetViewportBoundsDelta| will be on a viewport layer. + LayerTreeImpl::ViewportLayerIds viewport_ids; + viewport_ids.inner_viewport_container = root->id(); + host_impl.active_tree()->SetViewportLayersFromIds(viewport_ids); + + root->SetMasksToBounds(true); + host_impl.active_tree()->property_trees()->needs_rebuild = true; + host_impl.active_tree()->BuildLayerListAndPropertyTreesForTesting(); + root->layer_tree_impl()->ResetAllChangeTracking(); + + // SetViewportBoundsDelta changes subtree only when masks_to_bounds is true. + root->SetViewportBoundsDelta(gfx::Vector2d(222, 333)); + EXPECT_TRUE(root->LayerPropertyChanged()); + EXPECT_TRUE(host_impl.active_tree()->property_trees()->full_tree_damaged); + + root->SetMasksToBounds(false); + host_impl.active_tree()->property_trees()->needs_rebuild = true; + host_impl.active_tree()->BuildLayerListAndPropertyTreesForTesting(); + root->layer_tree_impl()->ResetAllChangeTracking(); + + // SetViewportBoundsDelta does not change the subtree without masks_to_bounds. + root->SetViewportBoundsDelta(gfx::Vector2d(333, 444)); + EXPECT_TRUE(root->LayerPropertyChanged()); + EXPECT_FALSE(host_impl.active_tree()->property_trees()->full_tree_damaged); + + host_impl.active_tree()->property_trees()->needs_rebuild = true; + host_impl.active_tree()->BuildLayerListAndPropertyTreesForTesting(); + root->layer_tree_impl()->ResetAllChangeTracking(); + + // Ensure some node is affected by the inner viewport bounds delta. This + // ensures the later call to |SetViewportBoundsDelta| will require a + // transform tree update. + TransformTree& transform_tree = + host_impl.active_tree()->property_trees()->transform_tree; + transform_tree.AddNodeAffectedByInnerViewportBoundsDelta( + child->transform_tree_index()); + EXPECT_FALSE(transform_tree.needs_update()); + root->SetViewportBoundsDelta(gfx::Vector2d(111, 222)); + EXPECT_TRUE(transform_tree.needs_update()); + + host_impl.active_tree()->property_trees()->needs_rebuild = true; + host_impl.active_tree()->BuildLayerListAndPropertyTreesForTesting(); + root->layer_tree_impl()->ResetAllChangeTracking(); + + // Ensure scrolling changes the transform tree but does not damage all trees. + root->ScrollBy(gfx::Vector2d(7, 9)); + EXPECT_TRUE(transform_tree.needs_update()); + EXPECT_TRUE(root->LayerPropertyChanged()); + EXPECT_FALSE(host_impl.active_tree()->property_trees()->full_tree_damaged); } TEST(LayerImplTest, VerifyNeedsUpdateDrawProperties) {
diff --git a/cc/output/ca_layer_overlay.cc b/cc/output/ca_layer_overlay.cc index 972c8c40..3e99264 100644 --- a/cc/output/ca_layer_overlay.cc +++ b/cc/output/ca_layer_overlay.cc
@@ -168,6 +168,7 @@ ca_layer_overlay->contents_rect = quad->tex_coord_rect; ca_layer_overlay->contents_rect.Scale(1.f / quad->texture_size.width(), 1.f / quad->texture_size.height()); + ca_layer_overlay->filter = quad->nearest_neighbor ? GL_NEAREST : GL_LINEAR; return CA_LAYER_SUCCESS; }
diff --git a/cc/output/dc_layer_overlay.cc b/cc/output/dc_layer_overlay.cc index 7cf6872..e5a043d 100644 --- a/cc/output/dc_layer_overlay.cc +++ b/cc/output/dc_layer_overlay.cc
@@ -205,6 +205,7 @@ } overlay_damage_rect->Union(quad_rectangle); + RecordDCLayerResult(DC_LAYER_SUCCESS); ca_layer_overlays->push_back(ca_layer); // Only allow one overlay for now. break;
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc index 7c3232532..858aee6 100644 --- a/cc/trees/layer_tree_impl.cc +++ b/cc/trees/layer_tree_impl.cc
@@ -178,11 +178,11 @@ // If pending tree topology changed and we still want to notify the pending // tree about scroll offset in the active tree, we may not find the // corresponding pending layer. - if (LayerById(layer_id)) { + if (auto* layer = LayerById(layer_id)) { // TODO(sunxd): when we have a layer_id to property_tree index map in // property trees, use the transform_id parameter instead of looking for // indices from LayerImpls. - transform_id = LayerById(layer_id)->transform_tree_index(); + transform_id = layer->transform_tree_index(); } else { DCHECK(!IsActiveTree()); return; @@ -219,9 +219,6 @@ int scroll_layer_id, clip_layer_id; if (IsViewportLayerId(layer_id)) { - if (!InnerViewportContainerLayer()) - return; - // For scrollbar purposes, a change to any of the four viewport layers // should affect the scrollbars tied to the outermost layers, which express // the sum of the entire viewport. @@ -258,11 +255,15 @@ return; gfx::ScrollOffset current_offset = scroll_layer->CurrentScrollOffset(); - if (IsViewportLayerId(scroll_layer_id)) { + float viewport_vertical_adjust = 0; + + bool is_viewport_scrollbar = scroll_layer->is_viewport_layer_type(); + if (is_viewport_scrollbar) { current_offset += InnerViewportScrollLayer()->CurrentScrollOffset(); if (OuterViewportContainerLayer()) clip_size.SetToMin(OuterViewportContainerLayer()->BoundsForScrolling()); clip_size.Scale(1 / current_page_scale_factor()); + viewport_vertical_adjust = clip_layer->ViewportBoundsDelta().y(); } bool y_offset_did_change = false; @@ -276,10 +277,10 @@ scrollbar->SetClipLayerLength(clip_size.height()); scrollbar->SetScrollLayerLength(scroll_size.height()); } - scrollbar->SetVerticalAdjust(clip_layer->ViewportBoundsDelta().y()); + scrollbar->SetVerticalAdjust(viewport_vertical_adjust); } - if (y_offset_did_change && IsViewportLayerId(scroll_layer_id)) + if (y_offset_did_change && is_viewport_scrollbar) TRACE_COUNTER_ID1("cc", "scroll_offset_y", scroll_layer->id(), current_offset.y()); } @@ -1246,6 +1247,7 @@ } void LayerTreeImpl::AddLayerShouldPushProperties(LayerImpl* layer) { + DCHECK(!IsActiveTree()) << "The active tree does not push layer properties"; layers_that_should_push_properties_.insert(layer); }
diff --git a/chrome/VERSION b/chrome/VERSION index b5cad96..e89d9d4 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=61 MINOR=0 -BUILD=3116 +BUILD=3117 PATCH=0
diff --git a/chrome/android/java/res/layout/translate_menu_item_checked.xml b/chrome/android/java/res/layout/translate_menu_item_checked.xml index 39705a4..64b527f6 100644 --- a/chrome/android/java/res/layout/translate_menu_item_checked.xml +++ b/chrome/android/java/res/layout/translate_menu_item_checked.xml
@@ -14,6 +14,16 @@ android:layout_width="match_parent" android:layout_height="?android:attr/listPreferredItemHeightSmall" > + <TextView + android:id="@+id/menu_item_text" + android:textAppearance="?android:attr/textAppearanceLargePopupMenu" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:layout_gravity="start" + android:gravity="center_vertical" + android:singleLine="true" + android:paddingEnd="16dp" /> <org.chromium.chrome.browser.widget.TintedImageView android:id="@+id/menu_item_icon" android:src="@drawable/ic_check_googblue_24dp" @@ -22,15 +32,6 @@ android:layout_gravity="end" android:gravity="center_vertical" chrome:chrometint="@color/dark_mode_tint" /> - <TextView - android:id="@+id/menu_item_text" - android:textAppearance="?android:attr/textAppearanceLargePopupMenu" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:layout_gravity="start" - android:gravity="center_vertical" - android:singleLine="true" - android:paddingStart="16dp" /> </LinearLayout>
diff --git a/chrome/android/webapk/strings/android_webapk_strings.grd b/chrome/android/webapk/strings/android_webapk_strings.grd index 8461366..40f53e5 100644 --- a/chrome/android/webapk/strings/android_webapk_strings.grd +++ b/chrome/android/webapk/strings/android_webapk_strings.grd
@@ -95,7 +95,7 @@ <messages fallback_to_english="true"> <!-- Select host browser dialog --> <message name="IDS_CHOOSE_HOST_BROWSER_DIALOG_TITLE" desc="Title for the host browser picker dialog, which is used to ask users to pick a browser to launch the installed WebAPK."> - <ph name="WEBAPK_SITE">%1$s<ex>Housing.com</ex></ph> needs a Web browser to run + <ph name="WEBAPK_SITE">%1$s<ex>Housing.com</ex></ph> needs a web browser to run </message> <message name="IDS_CHOOSE_HOST_BROWSER" desc="Content for the host browser picker dialog, which is used to ask users to pick a browser to launch the installed WebAPK."> Please select the browser you'd like to use to run <ph name="WEBAPK_SITE">%1$s<ex>Housing.com</ex></ph>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 057e884..d4ed886 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -2182,6 +2182,8 @@ "android/offline_pages/request_coordinator_factory.h", "offline_pages/background_loader_offliner.cc", "offline_pages/background_loader_offliner.h", + "offline_pages/prefetch/prefetch_service_factory.cc", + "offline_pages/prefetch/prefetch_service_factory.h", ] if (is_android) { sources += [ @@ -2190,7 +2192,6 @@ ] } deps += [ - "//components/offline_pages/content", "//components/offline_pages/content/background_loader", "//components/offline_pages/core", "//components/offline_pages/core/background:background_offliner",
diff --git a/chrome/browser/android/offline_pages/prefetch/prefetch_background_task.cc b/chrome/browser/android/offline_pages/prefetch/prefetch_background_task.cc index 17870fc..e2ad52e 100644 --- a/chrome/browser/android/offline_pages/prefetch/prefetch_background_task.cc +++ b/chrome/browser/android/offline_pages/prefetch/prefetch_background_task.cc
@@ -4,9 +4,9 @@ #include "chrome/browser/android/offline_pages/prefetch/prefetch_background_task.h" +#include "chrome/browser/offline_pages/prefetch/prefetch_service_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_android.h" -#include "components/offline_pages/content/prefetch_service_factory.h" #include "components/offline_pages/core/prefetch/prefetch_service.h" #include "content/public/browser/browser_context.h" #include "jni/PrefetchBackgroundTask_jni.h"
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm index f6417c0..89d8409 100644 --- a/chrome/browser/app_controller_mac.mm +++ b/chrome/browser/app_controller_mac.mm
@@ -965,7 +965,6 @@ // profile cannot have a browser. if (IsProfileSignedOut(lastProfile) || lastProfile->IsSystemProfile()) { UserManager::Show(base::FilePath(), - profiles::USER_MANAGER_NO_TUTORIAL, profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); return; } @@ -1170,7 +1169,6 @@ if (lastProfile->IsGuestSession() || IsProfileSignedOut(lastProfile) || lastProfile->IsSystemProfile()) { UserManager::Show(base::FilePath(), - profiles::USER_MANAGER_NO_TUTORIAL, profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); } else { CreateBrowser(lastProfile); @@ -1342,7 +1340,6 @@ } else { // No way to create a browser, default to the User Manager. UserManager::Show(base::FilePath(), - profiles::USER_MANAGER_NO_TUTORIAL, profiles::USER_MANAGER_SELECT_PROFILE_CHROME_SETTINGS); } } @@ -1356,7 +1353,6 @@ } else { // No way to create a browser, default to the User Manager. UserManager::Show(base::FilePath(), - profiles::USER_MANAGER_NO_TUTORIAL, profiles::USER_MANAGER_SELECT_PROFILE_ABOUT_CHROME); } }
diff --git a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc index 03d55d7da..35c9f79a 100644 --- a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc +++ b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc
@@ -240,7 +240,6 @@ void ExtensionAppShimHandler::Delegate::LaunchUserManager() { UserManager::Show(base::FilePath(), - profiles::USER_MANAGER_NO_TUTORIAL, profiles::USER_MANAGER_SELECT_PROFILE_APP_LAUNCHER); }
diff --git a/chrome/browser/background/background_mode_manager.cc b/chrome/browser/background/background_mode_manager.cc index dd819bc..b2f6fdd9 100644 --- a/chrome/browser/background/background_mode_manager.cc +++ b/chrome/browser/background/background_mode_manager.cc
@@ -644,7 +644,6 @@ chrome::ShowAboutChrome(bmd->GetBrowserWindow()); } else { UserManager::Show(base::FilePath(), - profiles::USER_MANAGER_NO_TUTORIAL, profiles::USER_MANAGER_SELECT_PROFILE_ABOUT_CHROME); } break; @@ -654,7 +653,6 @@ chrome::OpenTaskManager(bmd->GetBrowserWindow()); } else { UserManager::Show(base::FilePath(), - profiles::USER_MANAGER_NO_TUTORIAL, profiles::USER_MANAGER_SELECT_PROFILE_TASK_MANAGER); } break; @@ -683,7 +681,6 @@ bmd->ExecuteCommand(command_id, event_flags); } else { UserManager::Show(base::FilePath(), - profiles::USER_MANAGER_NO_TUTORIAL, profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); } break;
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index f22e7aa..10c3cc3 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -977,8 +977,6 @@ "login/ui/user_adding_screen_input_methods_controller.h", "login/ui/web_contents_forced_title.cc", "login/ui/web_contents_forced_title.h", - "login/ui/web_contents_set_background_color.cc", - "login/ui/web_contents_set_background_color.h", "login/ui/webui_login_display.cc", "login/ui/webui_login_display.h", "login/ui/webui_login_view.cc",
diff --git a/chrome/browser/chromeos/login/ui/webui_login_view.cc b/chrome/browser/chromeos/login/ui/webui_login_view.cc index 89d498d..78e038c8 100644 --- a/chrome/browser/chromeos/login/ui/webui_login_view.cc +++ b/chrome/browser/chromeos/login/ui/webui_login_view.cc
@@ -25,7 +25,6 @@ #include "chrome/browser/chromeos/login/ui/preloaded_web_view_factory.h" #include "chrome/browser/chromeos/login/ui/proxy_settings_dialog.h" #include "chrome/browser/chromeos/login/ui/web_contents_forced_title.h" -#include "chrome/browser/chromeos/login/ui/web_contents_set_background_color.h" #include "chrome/browser/chromeos/login/ui/webui_login_display.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h" @@ -57,6 +56,7 @@ #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #include "ui/keyboard/keyboard_controller.h" +#include "ui/views/controls/webview/web_contents_set_background_color.h" #include "ui/views/controls/webview/webview.h" #include "ui/views/widget/widget.h" @@ -220,7 +220,7 @@ if (!title.empty()) WebContentsForcedTitle::CreateForWebContentsWithTitle(web_contents, title); - WebContentsSetBackgroundColor::CreateForWebContentsWithColor( + views::WebContentsSetBackgroundColor::CreateForWebContentsWithColor( web_contents, SK_ColorTRANSPARENT); // Ensure that the login UI has a tab ID, which will allow the GAIA auth
diff --git a/chrome/browser/chromeos/printing/printer_configurer.h b/chrome/browser/chromeos/printing/printer_configurer.h index bd97c26..1bfcb039 100644 --- a/chrome/browser/chromeos/printing/printer_configurer.h +++ b/chrome/browser/chromeos/printing/printer_configurer.h
@@ -14,6 +14,8 @@ namespace chromeos { +// These values are written to logs. New enum values can be added, but existing +// enums must never be renumbered or deleted and reused. enum PrinterSetupResult { kFatalError = 0, // Setup failed in an unrecognized way kSuccess = 1, // Printer set up successfully
diff --git a/chrome/browser/gcm/gcm_profile_service_factory.cc b/chrome/browser/gcm/gcm_profile_service_factory.cc index 0d55417..8a35e4d 100644 --- a/chrome/browser/gcm/gcm_profile_service_factory.cc +++ b/chrome/browser/gcm/gcm_profile_service_factory.cc
@@ -3,7 +3,6 @@ // found in the LICENSE file. #include "chrome/browser/gcm/gcm_profile_service_factory.h" - #include <memory> #include "base/sequenced_task_runner.h" @@ -15,6 +14,7 @@ #include "chrome/browser/signin/signin_manager_factory.h" #include "components/gcm_driver/gcm_profile_service.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/offline_pages/features/features.h" #include "components/signin/core/browser/profile_identity_provider.h" #include "components/signin/core/browser/signin_manager.h" #include "content/public/browser/browser_thread.h" @@ -26,6 +26,12 @@ #include "components/gcm_driver/gcm_client_factory.h" #endif +#if BUILDFLAG(ENABLE_OFFLINE_PAGES) +#include "chrome/browser/offline_pages/prefetch/prefetch_service_factory.h" +#include "components/offline_pages/core/prefetch/prefetch_gcm_app_handler.h" +#include "components/offline_pages/core/prefetch/prefetch_service.h" +#endif + namespace gcm { // static @@ -53,6 +59,9 @@ #if !defined(OS_ANDROID) DependsOn(LoginUIServiceFactory::GetInstance()); #endif +#if BUILDFLAG(ENABLE_OFFLINE_PAGES) + DependsOn(offline_pages::PrefetchServiceFactory::GetInstance()); +#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES) } GCMProfileServiceFactory::~GCMProfileServiceFactory() { @@ -67,10 +76,12 @@ base::CreateSequencedTaskRunnerWithTraits( {base::MayBlock(), base::TaskPriority::BACKGROUND, base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})); + std::unique_ptr<GCMProfileService> service = nullptr; #if defined(OS_ANDROID) - return new GCMProfileService(profile->GetPath(), blocking_task_runner); + service = base::WrapUnique( + new GCMProfileService(profile->GetPath(), blocking_task_runner)); #else - return new GCMProfileService( + service = base::WrapUnique(new GCMProfileService( profile->GetPrefs(), profile->GetPath(), profile->GetRequestContext(), chrome::GetChannel(), gcm::GetProductCategoryForSubtypes(profile->GetPrefs()), @@ -83,8 +94,20 @@ content::BrowserThread::UI), content::BrowserThread::GetTaskRunnerForThread( content::BrowserThread::IO), - blocking_task_runner); + blocking_task_runner)); #endif +#if BUILDFLAG(ENABLE_OFFLINE_PAGES) + offline_pages::PrefetchService* prefetch_service = + offline_pages::PrefetchServiceFactory::GetForBrowserContext(context); + if (prefetch_service != nullptr) { + offline_pages::PrefetchGCMHandler* prefetch_gcm_handler = + prefetch_service->GetPrefetchGCMHandler(); + service->driver()->AddAppHandler(prefetch_gcm_handler->GetAppId(), + prefetch_gcm_handler->AsGCMAppHandler()); + } +#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES) + + return service.release(); } content::BrowserContext* GCMProfileServiceFactory::GetBrowserContextToUse(
diff --git a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc index 30c0dd4..f9a93716 100644 --- a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc +++ b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
@@ -47,6 +47,7 @@ #include "components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h" #include "components/ntp_snippets/sessions/tab_delegate_sync_adapter.h" #include "components/ntp_snippets/user_classifier.h" +#include "components/offline_pages/features/features.h" #include "components/prefs/pref_service.h" #include "components/safe_json/safe_json_parser.h" #include "components/signin/core/browser/profile_oauth2_token_service.h" @@ -62,30 +63,25 @@ #if defined(OS_ANDROID) #include "chrome/browser/android/chrome_feature_list.h" #include "chrome/browser/android/ntp/ntp_snippets_launcher.h" -#include "chrome/browser/android/offline_pages/offline_page_model_factory.h" -#include "chrome/browser/android/offline_pages/request_coordinator_factory.h" #include "chrome/browser/download/download_core_service.h" #include "chrome/browser/download/download_core_service_factory.h" #include "chrome/browser/download/download_history.h" #include "chrome/browser/ntp_snippets/download_suggestions_provider.h" -#include "components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h" #include "components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h" -#include "components/offline_pages/content/suggested_articles_observer.h" +#include "components/physical_web/data_source/physical_web_data_source.h" +#endif + +#if BUILDFLAG(ENABLE_OFFLINE_PAGES) +#include "chrome/browser/android/offline_pages/offline_page_model_factory.h" +#include "chrome/browser/android/offline_pages/request_coordinator_factory.h" +#include "chrome/browser/offline_pages/prefetch/prefetch_service_factory.h" +#include "components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h" #include "components/offline_pages/core/background/request_coordinator.h" #include "components/offline_pages/core/offline_page_feature.h" #include "components/offline_pages/core/offline_page_model.h" +#include "components/offline_pages/core/prefetch/suggested_articles_observer.h" #include "components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.h" -#include "components/physical_web/data_source/physical_web_data_source.h" - -using content::DownloadManager; -using ntp_snippets::PhysicalWebPageSuggestionsProvider; -using ntp_snippets::RecentTabSuggestionsProvider; -using offline_pages::OfflinePageModel; -using offline_pages::RequestCoordinator; -using offline_pages::OfflinePageModelFactory; -using offline_pages::RequestCoordinatorFactory; -using physical_web::PhysicalWebDataSource; -#endif // OS_ANDROID +#endif using bookmarks::BookmarkModel; using content::BrowserThread; @@ -108,6 +104,20 @@ using syncer::SyncService; using translate::LanguageModel; +#if defined(OS_ANDROID) +using content::DownloadManager; +using ntp_snippets::PhysicalWebPageSuggestionsProvider; +using physical_web::PhysicalWebDataSource; +#endif // OS_ANDROID + +#if BUILDFLAG(ENABLE_OFFLINE_PAGES) +using ntp_snippets::RecentTabSuggestionsProvider; +using offline_pages::OfflinePageModel; +using offline_pages::RequestCoordinator; +using offline_pages::OfflinePageModelFactory; +using offline_pages::RequestCoordinatorFactory; +#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES) + // For now, ContentSuggestionsService must only be instantiated on Android. // See also crbug.com/688366. #if defined(OS_ANDROID) @@ -130,7 +140,7 @@ #endif } -#if defined(OS_ANDROID) +#if BUILDFLAG(ENABLE_OFFLINE_PAGES) bool IsRecentTabProviderEnabled() { return base::FeatureList::IsEnabled( @@ -151,6 +161,10 @@ service->RegisterProvider(std::move(provider)); } +#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES) + +#if defined(OS_ANDROID) + void RegisterDownloadsProvider(OfflinePageModel* offline_page_model, DownloadManager* download_manager, DownloadHistory* download_history, @@ -285,9 +299,10 @@ DependsOn(BookmarkModelFactory::GetInstance()); DependsOn(HistoryServiceFactory::GetInstance()); DependsOn(LargeIconServiceFactory::GetInstance()); -#if defined(OS_ANDROID) +#if BUILDFLAG(ENABLE_OFFLINE_PAGES) DependsOn(OfflinePageModelFactory::GetInstance()); -#endif // OS_ANDROID + DependsOn(offline_pages::PrefetchServiceFactory::GetInstance()); +#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES) DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance()); DependsOn(ProfileSyncServiceFactory::GetInstance()); DependsOn(SigninManagerFactory::GetInstance()); @@ -332,7 +347,7 @@ pref_service, std::move(category_ranker), std::move(user_classifier), std::move(scheduler)); -#if defined(OS_ANDROID) +#if BUILDFLAG(ENABLE_OFFLINE_PAGES) OfflinePageModel* offline_page_model = OfflinePageModelFactory::GetForBrowserContext(profile); if (IsRecentTabProviderEnabled()) { @@ -342,6 +357,12 @@ pref_service); } + offline_pages::PrefetchService* prefetch_service = + offline_pages::PrefetchServiceFactory::GetForBrowserContext(profile); + prefetch_service->ObserveContentSuggestionsService(service); +#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES) + +#if defined(OS_ANDROID) bool show_asset_downloads = !IsChromeHomeEnabled() && base::FeatureList::IsEnabled(features::kAssetDownloadSuggestionsFeature); @@ -361,9 +382,6 @@ show_asset_downloads ? download_manager : nullptr, download_history, service, pref_service); } - - offline_pages::SuggestedArticlesObserver::ObserveContentSuggestionsService( - profile, service); #endif // OS_ANDROID // |bookmark_model| can be null in tests.
diff --git a/components/offline_pages/content/prefetch_service_factory.cc b/chrome/browser/offline_pages/prefetch/prefetch_service_factory.cc similarity index 80% rename from components/offline_pages/content/prefetch_service_factory.cc rename to chrome/browser/offline_pages/prefetch/prefetch_service_factory.cc index ffe46b26..76e0722 100644 --- a/components/offline_pages/content/prefetch_service_factory.cc +++ b/chrome/browser/offline_pages/prefetch/prefetch_service_factory.cc
@@ -2,10 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/offline_pages/content/prefetch_service_factory.h" +#include "chrome/browser/offline_pages/prefetch/prefetch_service_factory.h" +#include "base/memory/ptr_util.h" #include "base/memory/singleton.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/offline_pages/core/prefetch/prefetch_gcm_app_handler.h" #include "components/offline_pages/core/prefetch/prefetch_service_impl.h" #include "content/public/browser/browser_context.h" @@ -15,7 +17,6 @@ : BrowserContextKeyedServiceFactory( "OfflinePagePrefetchService", BrowserContextDependencyManager::GetInstance()) {} - // static PrefetchServiceFactory* PrefetchServiceFactory::GetInstance() { return base::Singleton<PrefetchServiceFactory>::get(); @@ -30,7 +31,7 @@ KeyedService* PrefetchServiceFactory::BuildServiceInstanceFor( content::BrowserContext* context) const { - return new PrefetchServiceImpl(); + return new PrefetchServiceImpl(base::MakeUnique<PrefetchGCMAppHandler>()); } } // namespace offline_pages
diff --git a/components/offline_pages/content/prefetch_service_factory.h b/chrome/browser/offline_pages/prefetch/prefetch_service_factory.h similarity index 83% rename from components/offline_pages/content/prefetch_service_factory.h rename to chrome/browser/offline_pages/prefetch/prefetch_service_factory.h index c7f4fb16..dac9fe12 100644 --- a/components/offline_pages/content/prefetch_service_factory.h +++ b/chrome/browser/offline_pages/prefetch/prefetch_service_factory.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_OFFLINE_PAGES_CONTENT_PREFETCH_SERVICE_FACTORY_H_ -#define COMPONENTS_OFFLINE_PAGES_CONTENT_PREFETCH_SERVICE_FACTORY_H_ +#ifndef CHROME_BROWSER_OFFLINE_PAGES_PREFETCH_PREFETCH_SERVICE_FACTORY_H_ +#define CHROME_BROWSER_OFFLINE_PAGES_PREFETCH_PREFETCH_SERVICE_FACTORY_H_ #include "base/macros.h" #include "components/keyed_service/content/browser_context_keyed_service_factory.h" @@ -40,4 +40,4 @@ } // namespace offline_pages -#endif // COMPONENTS_OFFLINE_PAGES_CONTENT_PREFETCH_SERVICE_FACTORY_H_ +#endif // CHROME_BROWSER_OFFLINE_PAGES_PREFETCH_PREFETCH_SERVICE_FACTORY_H_
diff --git a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc index 89b97bcb..07d663c 100644 --- a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.h" +#include "chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.h" #include "chrome/browser/page_load_metrics/page_load_metrics_util.h" #include "third_party/WebKit/public/platform/WebLoadingBehaviorFlag.h" @@ -23,6 +24,12 @@ const char kHistogramServiceWorkerParseStartToFirstContentfulPaint[] = "PageLoad.Clients.ServiceWorker.PaintTiming." "ParseStartToFirstContentfulPaint"; +const char kHistogramServiceWorkerFirstMeaningfulPaint[] = + "PageLoad.Clients.ServiceWorker.Experimental.PaintTiming." + "NavigationToFirstMeaningfulPaint"; +const char kHistogramServiceWorkerParseStartToFirstMeaningfulPaint[] = + "PageLoad.Clients.ServiceWorker.Experimental.PaintTiming." + "ParseStartToFirstMeaningfulPaint"; const char kHistogramServiceWorkerDomContentLoaded[] = "PageLoad.Clients.ServiceWorker.DocumentTiming." "NavigationToDOMContentLoadedEventFired"; @@ -35,6 +42,12 @@ const char kHistogramServiceWorkerParseStartToFirstContentfulPaintInbox[] = "PageLoad.Clients.ServiceWorker.PaintTiming." "ParseStartToFirstContentfulPaint.inbox"; +const char kHistogramServiceWorkerFirstMeaningfulPaintInbox[] = + "PageLoad.Clients.ServiceWorker.Experimental.PaintTiming." + "NavigationToFirstMeaningfulPaint.inbox"; +const char kHistogramServiceWorkerParseStartToFirstMeaningfulPaintInbox[] = + "PageLoad.Clients.ServiceWorker.Experimental.PaintTiming." + "ParseStartToFirstMeaningfulPaint.inbox"; const char kHistogramServiceWorkerDomContentLoadedInbox[] = "PageLoad.Clients.ServiceWorker.DocumentTiming." "NavigationToDOMContentLoadedEventFired.inbox"; @@ -42,6 +55,25 @@ "PageLoad.Clients.ServiceWorker.DocumentTiming.NavigationToLoadEventFired." "inbox"; +const char kHistogramServiceWorkerFirstContentfulPaintSearch[] = + "PageLoad.Clients.ServiceWorker.PaintTiming." + "NavigationToFirstContentfulPaint.search"; +const char kHistogramServiceWorkerParseStartToFirstContentfulPaintSearch[] = + "PageLoad.Clients.ServiceWorker.PaintTiming." + "ParseStartToFirstContentfulPaint.search"; +const char kHistogramServiceWorkerFirstMeaningfulPaintSearch[] = + "PageLoad.Clients.ServiceWorker.Experimental.PaintTiming." + "NavigationToFirstMeaningfulPaint.search"; +const char kHistogramServiceWorkerParseStartToFirstMeaningfulPaintSearch[] = + "PageLoad.Clients.ServiceWorker.Experimental.PaintTiming." + "ParseStartToFirstMeaningfulPaint.search"; +const char kHistogramServiceWorkerDomContentLoadedSearch[] = + "PageLoad.Clients.ServiceWorker.DocumentTiming." + "NavigationToDOMContentLoadedEventFired.search"; +const char kHistogramServiceWorkerLoadSearch[] = + "PageLoad.Clients.ServiceWorker.DocumentTiming.NavigationToLoadEventFired." + "search"; + } // namespace internal namespace { @@ -88,6 +120,50 @@ internal::kHistogramServiceWorkerParseStartToFirstContentfulPaintInbox, timing.paint_timing->first_contentful_paint.value() - timing.parse_timing->parse_start.value()); + } else if (FromGWSPageLoadMetricsLogger::IsGoogleSearchResultUrl(info.url)) { + PAGE_LOAD_HISTOGRAM( + internal::kHistogramServiceWorkerFirstContentfulPaintSearch, + timing.paint_timing->first_contentful_paint.value()); + PAGE_LOAD_HISTOGRAM( + internal::kHistogramServiceWorkerParseStartToFirstContentfulPaintSearch, + timing.paint_timing->first_contentful_paint.value() - + timing.parse_timing->parse_start.value()); + } +} + +void ServiceWorkerPageLoadMetricsObserver:: + OnFirstMeaningfulPaintInMainFrameDocument( + const page_load_metrics::mojom::PageLoadTiming& timing, + const page_load_metrics::PageLoadExtraInfo& info) { + if (!IsServiceWorkerControlled(info)) + return; + if (!WasStartedInForegroundOptionalEventInForeground( + timing.paint_timing->first_meaningful_paint, info)) { + return; + } + PAGE_LOAD_HISTOGRAM(internal::kHistogramServiceWorkerFirstMeaningfulPaint, + timing.paint_timing->first_meaningful_paint.value()); + PAGE_LOAD_HISTOGRAM( + internal::kHistogramServiceWorkerParseStartToFirstMeaningfulPaint, + timing.paint_timing->first_meaningful_paint.value() - + timing.parse_timing->parse_start.value()); + + if (IsInboxSite(info.url)) { + PAGE_LOAD_HISTOGRAM( + internal::kHistogramServiceWorkerFirstMeaningfulPaintInbox, + timing.paint_timing->first_meaningful_paint.value()); + PAGE_LOAD_HISTOGRAM( + internal::kHistogramServiceWorkerParseStartToFirstMeaningfulPaintInbox, + timing.paint_timing->first_meaningful_paint.value() - + timing.parse_timing->parse_start.value()); + } else if (FromGWSPageLoadMetricsLogger::IsGoogleSearchResultUrl(info.url)) { + PAGE_LOAD_HISTOGRAM( + internal::kHistogramServiceWorkerFirstMeaningfulPaintSearch, + timing.paint_timing->first_meaningful_paint.value()); + PAGE_LOAD_HISTOGRAM( + internal::kHistogramServiceWorkerParseStartToFirstMeaningfulPaintSearch, + timing.paint_timing->first_meaningful_paint.value() - + timing.parse_timing->parse_start.value()); } } @@ -107,6 +183,10 @@ PAGE_LOAD_HISTOGRAM( internal::kHistogramServiceWorkerDomContentLoadedInbox, timing.document_timing->dom_content_loaded_event_start.value()); + } else if (FromGWSPageLoadMetricsLogger::IsGoogleSearchResultUrl(info.url)) { + PAGE_LOAD_HISTOGRAM( + internal::kHistogramServiceWorkerDomContentLoadedSearch, + timing.document_timing->dom_content_loaded_event_start.value()); } } @@ -123,6 +203,9 @@ if (IsInboxSite(info.url)) { PAGE_LOAD_HISTOGRAM(internal::kHistogramServiceWorkerLoadInbox, timing.document_timing->load_event_start.value()); + } else if (FromGWSPageLoadMetricsLogger::IsGoogleSearchResultUrl(info.url)) { + PAGE_LOAD_HISTOGRAM(internal::kHistogramServiceWorkerLoadSearch, + timing.document_timing->load_event_start.value()); } }
diff --git a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.h index 8e1b9f2..b6b974d3 100644 --- a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.h +++ b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.h
@@ -16,14 +16,29 @@ extern const char kHistogramServiceWorkerFirstContentfulPaint[]; extern const char kBackgroundHistogramServiceWorkerFirstContentfulPaint[]; extern const char kHistogramServiceWorkerParseStartToFirstContentfulPaint[]; +extern const char kHistogramServiceWorkerFirstMeaningfulPaint[]; +extern const char kHistogramServiceWorkerParseStartToFirstMeaningfulPaint[]; extern const char kHistogramServiceWorkerDomContentLoaded[]; extern const char kHistogramServiceWorkerLoad[]; + extern const char kHistogramServiceWorkerFirstContentfulPaintInbox[]; +extern const char kHistogramServiceWorkerFirstMeaningfulPaintInbox[]; +extern const char + kHistogramServiceWorkerParseStartToFirstMeaningfulPaintInbox[]; extern const char kHistogramServiceWorkerParseStartToFirstContentfulPaintInbox[]; extern const char kHistogramServiceWorkerDomContentLoadedInbox[]; extern const char kHistogramServiceWorkerLoadInbox[]; +extern const char kHistogramServiceWorkerFirstContentfulPaintSearch[]; +extern const char kHistogramServiceWorkerFirstMeaningfulPaintSearch[]; +extern const char + kHistogramServiceWorkerParseStartToFirstMeaningfulPaintSearch[]; +extern const char + kHistogramServiceWorkerParseStartToFirstContentfulPaintSearch[]; +extern const char kHistogramServiceWorkerDomContentLoadedSearch[]; +extern const char kHistogramServiceWorkerLoadSearch[]; + } // namespace internal class ServiceWorkerPageLoadMetricsObserver @@ -37,6 +52,9 @@ void OnFirstContentfulPaintInPage( const page_load_metrics::mojom::PageLoadTiming& timing, const page_load_metrics::PageLoadExtraInfo& extra_info) override; + void OnFirstMeaningfulPaintInMainFrameDocument( + const page_load_metrics::mojom::PageLoadTiming& timing, + const page_load_metrics::PageLoadExtraInfo& info) override; void OnDomContentLoadedEventStart( const page_load_metrics::mojom::PageLoadTiming& timing, const page_load_metrics::PageLoadExtraInfo& extra_info) override;
diff --git a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer_unittest.cc index 39a7f6e2..3074e0c3 100644 --- a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer_unittest.cc +++ b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer_unittest.cc
@@ -11,6 +11,7 @@ const char kDefaultTestUrl[] = "https://google.com"; const char kInboxTestUrl[] = "https://inbox.google.com/test"; +const char kSearchTestUrl[] = "https://www.google.com/search?q=test"; } // namespace @@ -37,6 +38,10 @@ histogram_tester().ExpectTotalCount( internal::kHistogramServiceWorkerParseStartToFirstContentfulPaint, 0); histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerFirstMeaningfulPaint, 0); + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerParseStartToFirstMeaningfulPaint, 0); + histogram_tester().ExpectTotalCount( internal::kHistogramServiceWorkerDomContentLoaded, 0); histogram_tester().ExpectTotalCount(internal::kHistogramServiceWorkerLoad, 0); @@ -53,11 +58,33 @@ internal::kHistogramServiceWorkerParseStartToFirstContentfulPaintInbox, 0); histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerFirstMeaningfulPaintInbox, 0); + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerParseStartToFirstMeaningfulPaintInbox, + 0); + histogram_tester().ExpectTotalCount( internal::kHistogramServiceWorkerDomContentLoadedInbox, 0); histogram_tester().ExpectTotalCount( internal::kHistogramServiceWorkerLoadInbox, 0); } + void AssertNoSearchHistogramsLogged() { + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerFirstContentfulPaintSearch, 0); + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerParseStartToFirstContentfulPaintSearch, + 0); + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerFirstMeaningfulPaintSearch, 0); + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerParseStartToFirstMeaningfulPaintSearch, + 0); + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerDomContentLoadedSearch, 0); + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerLoadSearch, 0); + } + void InitializeTestPageLoadTiming( page_load_metrics::mojom::PageLoadTiming* timing) { page_load_metrics::InitPageLoadTimingForTest(timing); @@ -65,6 +92,8 @@ timing->parse_timing->parse_start = base::TimeDelta::FromMilliseconds(100); timing->paint_timing->first_contentful_paint = base::TimeDelta::FromMilliseconds(300); + timing->paint_timing->first_meaningful_paint = + base::TimeDelta::FromMilliseconds(700); timing->document_timing->dom_content_loaded_event_start = base::TimeDelta::FromMilliseconds(600); timing->document_timing->load_event_start = @@ -76,6 +105,7 @@ TEST_F(ServiceWorkerPageLoadMetricsObserverTest, NoMetrics) { AssertNoServiceWorkerHistogramsLogged(); AssertNoInboxHistogramsLogged(); + AssertNoSearchHistogramsLogged(); } TEST_F(ServiceWorkerPageLoadMetricsObserverTest, NoServiceWorker) { @@ -87,6 +117,7 @@ AssertNoServiceWorkerHistogramsLogged(); AssertNoInboxHistogramsLogged(); + AssertNoSearchHistogramsLogged(); } TEST_F(ServiceWorkerPageLoadMetricsObserverTest, WithServiceWorker) { @@ -134,6 +165,7 @@ internal::kHistogramServiceWorkerParseStart, 1); AssertNoInboxHistogramsLogged(); + AssertNoSearchHistogramsLogged(); } TEST_F(ServiceWorkerPageLoadMetricsObserverTest, WithServiceWorkerBackground) { @@ -165,6 +197,10 @@ histogram_tester().ExpectTotalCount( internal::kHistogramServiceWorkerParseStartToFirstContentfulPaint, 0); histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerFirstMeaningfulPaint, 0); + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerParseStartToFirstMeaningfulPaint, 0); + histogram_tester().ExpectTotalCount( internal::kHistogramServiceWorkerDomContentLoaded, 0); histogram_tester().ExpectTotalCount(internal::kHistogramServiceWorkerLoad, 0); // TODO(crbug.com/686590): The following expectation fails on Win7 Tests @@ -173,6 +209,7 @@ // internal::kBackgroundHistogramServiceWorkerParseStart, 1); AssertNoInboxHistogramsLogged(); + AssertNoSearchHistogramsLogged(); } TEST_F(ServiceWorkerPageLoadMetricsObserverTest, InboxSite) { @@ -218,6 +255,35 @@ 1); histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerFirstMeaningfulPaint, 1); + histogram_tester().ExpectBucketCount( + internal::kHistogramServiceWorkerFirstMeaningfulPaint, + timing.paint_timing->first_meaningful_paint.value().InMilliseconds(), 1); + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerFirstMeaningfulPaintInbox, 1); + histogram_tester().ExpectBucketCount( + internal::kHistogramServiceWorkerFirstMeaningfulPaintInbox, + timing.paint_timing->first_meaningful_paint.value().InMilliseconds(), 1); + + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerParseStartToFirstMeaningfulPaint, 1); + histogram_tester().ExpectBucketCount( + internal::kHistogramServiceWorkerParseStartToFirstMeaningfulPaint, + (timing.paint_timing->first_meaningful_paint.value() - + timing.parse_timing->parse_start.value()) + .InMilliseconds(), + 1); + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerParseStartToFirstMeaningfulPaintInbox, + 1); + histogram_tester().ExpectBucketCount( + internal::kHistogramServiceWorkerParseStartToFirstMeaningfulPaintInbox, + (timing.paint_timing->first_meaningful_paint.value() - + timing.parse_timing->parse_start.value()) + .InMilliseconds(), + 1); + + histogram_tester().ExpectTotalCount( internal::kHistogramServiceWorkerDomContentLoaded, 1); histogram_tester().ExpectBucketCount( internal::kHistogramServiceWorkerDomContentLoaded, @@ -243,4 +309,107 @@ timing.document_timing->load_event_start.value().InMilliseconds(), 1); histogram_tester().ExpectTotalCount( internal::kHistogramServiceWorkerParseStart, 1); + + AssertNoSearchHistogramsLogged(); +} + +TEST_F(ServiceWorkerPageLoadMetricsObserverTest, SearchSite) { + page_load_metrics::mojom::PageLoadTiming timing; + InitializeTestPageLoadTiming(&timing); + + NavigateAndCommit(GURL(kSearchTestUrl)); + page_load_metrics::mojom::PageLoadMetadata metadata; + metadata.behavior_flags |= + blink::WebLoadingBehaviorFlag::kWebLoadingBehaviorServiceWorkerControlled; + SimulateTimingAndMetadataUpdate(timing, metadata); + + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerFirstContentfulPaint, 1); + histogram_tester().ExpectBucketCount( + internal::kHistogramServiceWorkerFirstContentfulPaint, + timing.paint_timing->first_contentful_paint.value().InMilliseconds(), 1); + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerFirstContentfulPaintSearch, 1); + histogram_tester().ExpectBucketCount( + internal::kHistogramServiceWorkerFirstContentfulPaintSearch, + timing.paint_timing->first_contentful_paint.value().InMilliseconds(), 1); + + histogram_tester().ExpectTotalCount( + internal::kBackgroundHistogramServiceWorkerFirstContentfulPaint, 0); + + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerParseStartToFirstContentfulPaint, 1); + histogram_tester().ExpectBucketCount( + internal::kHistogramServiceWorkerParseStartToFirstContentfulPaint, + (timing.paint_timing->first_contentful_paint.value() - + timing.parse_timing->parse_start.value()) + .InMilliseconds(), + 1); + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerParseStartToFirstContentfulPaintSearch, + 1); + histogram_tester().ExpectBucketCount( + internal::kHistogramServiceWorkerParseStartToFirstContentfulPaintSearch, + (timing.paint_timing->first_contentful_paint.value() - + timing.parse_timing->parse_start.value()) + .InMilliseconds(), + 1); + + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerFirstMeaningfulPaint, 1); + histogram_tester().ExpectBucketCount( + internal::kHistogramServiceWorkerFirstMeaningfulPaint, + timing.paint_timing->first_meaningful_paint.value().InMilliseconds(), 1); + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerFirstMeaningfulPaintSearch, 1); + histogram_tester().ExpectBucketCount( + internal::kHistogramServiceWorkerFirstMeaningfulPaintSearch, + timing.paint_timing->first_meaningful_paint.value().InMilliseconds(), 1); + + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerParseStartToFirstMeaningfulPaint, 1); + histogram_tester().ExpectBucketCount( + internal::kHistogramServiceWorkerParseStartToFirstMeaningfulPaint, + (timing.paint_timing->first_meaningful_paint.value() - + timing.parse_timing->parse_start.value()) + .InMilliseconds(), + 1); + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerParseStartToFirstMeaningfulPaintSearch, + 1); + histogram_tester().ExpectBucketCount( + internal::kHistogramServiceWorkerParseStartToFirstMeaningfulPaintSearch, + (timing.paint_timing->first_meaningful_paint.value() - + timing.parse_timing->parse_start.value()) + .InMilliseconds(), + 1); + + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerDomContentLoaded, 1); + histogram_tester().ExpectBucketCount( + internal::kHistogramServiceWorkerDomContentLoaded, + timing.document_timing->dom_content_loaded_event_start.value() + .InMilliseconds(), + 1); + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerDomContentLoadedSearch, 1); + histogram_tester().ExpectBucketCount( + internal::kHistogramServiceWorkerDomContentLoadedSearch, + timing.document_timing->dom_content_loaded_event_start.value() + .InMilliseconds(), + 1); + + histogram_tester().ExpectTotalCount(internal::kHistogramServiceWorkerLoad, 1); + histogram_tester().ExpectBucketCount( + internal::kHistogramServiceWorkerLoad, + timing.document_timing->load_event_start.value().InMilliseconds(), 1); + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerLoadSearch, 1); + histogram_tester().ExpectBucketCount( + internal::kHistogramServiceWorkerLoadSearch, + timing.document_timing->load_event_start.value().InMilliseconds(), 1); + histogram_tester().ExpectTotalCount( + internal::kHistogramServiceWorkerParseStart, 1); + + AssertNoInboxHistogramsLogged(); }
diff --git a/chrome/browser/profiles/avatar_menu.cc b/chrome/browser/profiles/avatar_menu.cc index 76a7cc3..43ed71ae 100644 --- a/chrome/browser/profiles/avatar_menu.cc +++ b/chrome/browser/profiles/avatar_menu.cc
@@ -113,7 +113,6 @@ // Don't open a browser window for signed-out profiles. if (item.signin_required) { UserManager::Show(item.profile_path, - profiles::USER_MANAGER_NO_TUTORIAL, profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); return; }
diff --git a/chrome/browser/profiles/profile_window.cc b/chrome/browser/profiles/profile_window.cc index 594dbf7b..4e36df9 100644 --- a/chrome/browser/profiles/profile_window.cc +++ b/chrome/browser/profiles/profile_window.cc
@@ -123,13 +123,11 @@ }; // Called after a |system_profile| is available to be used by the user manager. -// Based on the value of |tutorial_mode| we determine a url to be displayed -// by the webui and run the |callback|, if it exists. Depending on the value of +// Runs |callback|, if it exists. Depending on the value of // |user_manager_action|, executes an action once the user manager displays or // after a profile is opened. void OnUserManagerSystemProfileCreated( const base::FilePath& profile_path_to_focus, - profiles::UserManagerTutorialMode tutorial_mode, profiles::UserManagerAction user_manager_action, const base::Callback<void(Profile*, const std::string&)>& callback, Profile* system_profile, @@ -140,9 +138,7 @@ // Tell the webui which user should be focused. std::string page = chrome::kChromeUIMdUserManagerUrl; - if (tutorial_mode == profiles::USER_MANAGER_TUTORIAL_OVERVIEW) { - page += profiles::kUserManagerDisplayTutorial; - } else if (!profile_path_to_focus.empty()) { + if (!profile_path_to_focus.empty()) { // The file path is processed in the same way as base::CreateFilePathValue // (i.e. convert to std::string with AsUTF8Unsafe()), and then URI encoded. page += "#"; @@ -186,7 +182,6 @@ namespace profiles { // User Manager parameters are prefixed with hash. -const char kUserManagerDisplayTutorial[] = "#tutorial"; const char kUserManagerOpenCreateUserPage[] = "#create-user"; const char kUserManagerSelectProfileTaskManager[] = "#task-manager"; const char kUserManagerSelectProfileAboutChrome[] = "#about-chrome"; @@ -360,7 +355,6 @@ void ProfileBrowserCloseSuccess(const base::FilePath& profile_path) { UserManager::Show(base::FilePath(), - profiles::USER_MANAGER_NO_TUTORIAL, profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); } @@ -391,7 +385,6 @@ chrome::HideTaskManager(); UserManager::Show(profile_path, - profiles::USER_MANAGER_NO_TUTORIAL, profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); } @@ -447,7 +440,6 @@ void CreateSystemProfileForUserManager( const base::FilePath& profile_path_to_focus, - profiles::UserManagerTutorialMode tutorial_mode, profiles::UserManagerAction user_manager_action, const base::Callback<void(Profile*, const std::string&)>& callback) { // Create the system profile, if necessary, and open the User Manager @@ -456,7 +448,6 @@ ProfileManager::GetSystemProfilePath(), base::Bind(&OnUserManagerSystemProfileCreated, profile_path_to_focus, - tutorial_mode, user_manager_action, callback), base::string16(), @@ -464,24 +455,8 @@ std::string()); } -void ShowUserManagerMaybeWithTutorial(Profile* profile) { - // Guest users cannot appear in the User Manager, nor display a tutorial. - if (!profile || profile->IsGuestSession()) { - UserManager::Show(base::FilePath(), - profiles::USER_MANAGER_NO_TUTORIAL, - profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); - return; - } - UserManager::Show(base::FilePath(), - profiles::USER_MANAGER_TUTORIAL_OVERVIEW, - profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); -} - -void BubbleViewModeFromAvatarBubbleMode( - BrowserWindow::AvatarBubbleMode mode, - BubbleViewMode* bubble_view_mode, - TutorialMode* tutorial_mode) { - *tutorial_mode = TUTORIAL_MODE_NONE; +void BubbleViewModeFromAvatarBubbleMode(BrowserWindow::AvatarBubbleMode mode, + BubbleViewMode* bubble_view_mode) { switch (mode) { case BrowserWindow::AVATAR_BUBBLE_MODE_ACCOUNT_MANAGEMENT: *bubble_view_mode = BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT; @@ -497,27 +472,13 @@ return; case BrowserWindow::AVATAR_BUBBLE_MODE_CONFIRM_SIGNIN: *bubble_view_mode = BUBBLE_VIEW_MODE_PROFILE_CHOOSER; - *tutorial_mode = TUTORIAL_MODE_CONFIRM_SIGNIN; return; case BrowserWindow::AVATAR_BUBBLE_MODE_SHOW_ERROR: *bubble_view_mode = BUBBLE_VIEW_MODE_PROFILE_CHOOSER; - *tutorial_mode = TUTORIAL_MODE_SHOW_ERROR; return; default: *bubble_view_mode = profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER; } } -bool ShouldShowWelcomeUpgradeTutorial( - Profile* profile, TutorialMode tutorial_mode) { - const int show_count = profile->GetPrefs()->GetInteger( - prefs::kProfileAvatarTutorialShown); - // Do not show the tutorial if user has dismissed it. - if (show_count > signin_ui_util::kUpgradeWelcomeTutorialShowMax) - return false; - - return tutorial_mode == TUTORIAL_MODE_WELCOME_UPGRADE || - show_count != signin_ui_util::kUpgradeWelcomeTutorialShowMax; -} - } // namespace profiles
diff --git a/chrome/browser/profiles/profile_window.h b/chrome/browser/profiles/profile_window.h index 6f9ddaa8..ce1bc2c7 100644 --- a/chrome/browser/profiles/profile_window.h +++ b/chrome/browser/profiles/profile_window.h
@@ -18,13 +18,6 @@ namespace profiles { -// Different tutorials that can be displayed in the user manager. -enum UserManagerTutorialMode { - USER_MANAGER_NO_TUTORIAL, // Does not display a tutorial. - USER_MANAGER_TUTORIAL_OVERVIEW, // Basic overview of new features. - USER_MANAGER_TUTORIAL_LOCK, // TODO(noms): To be implemented. -}; - // Different actions to perform after the user manager selects a profile as well // as actions to perform when user manager window opens. The former have a // USER_MANAGER_SELECT_PROFILE_ prefix and the later a USER_MANAGER_OPEN_ @@ -38,7 +31,6 @@ USER_MANAGER_SELECT_PROFILE_APP_LAUNCHER, }; -extern const char kUserManagerDisplayTutorial[]; extern const char kUserManagerOpenCreateUserPage[]; extern const char kUserManagerSelectProfileTaskManager[]; extern const char kUserManagerSelectProfileAboutChrome[]; @@ -117,9 +109,7 @@ // Returns whether lock is available to this profile. bool IsLockAvailable(Profile* profile); -// Creates or reuses the system profile needed by the user manager. Based on -// the value of |tutorial_mode|, the user manager can show a specific -// tutorial, or no tutorial at all. If a tutorial is not shown, then +// Creates or reuses the system profile needed by the user manager. // |profile_path_to_focus| could be used to specify which user should be // focused. Depending on the value of |user_manager_action|, executes an action // once the user manager displays or after a profile is opened. |callback| is @@ -127,26 +117,13 @@ // profile. void CreateSystemProfileForUserManager( const base::FilePath& profile_path_to_focus, - profiles::UserManagerTutorialMode tutorial_mode, profiles::UserManagerAction user_manager_action, const base::Callback<void(Profile*, const std::string&)>& callback); -// Based on the |profile| preferences, determines whether a user manager -// tutorial needs to be shown, and displays the user manager with or without -// the tutorial. -void ShowUserManagerMaybeWithTutorial(Profile* profile); - // Converts from modes in the avatar menu to modes understood by // ProfileChooserView. -void BubbleViewModeFromAvatarBubbleMode( - BrowserWindow::AvatarBubbleMode mode, - BubbleViewMode* bubble_view_mode, - TutorialMode* tutorial_mode); - -// Returns true if the Welcome/Upgrade tutorial bubble should be shown to the -// user, false otherwise. -bool ShouldShowWelcomeUpgradeTutorial( - Profile* profile, TutorialMode tutorial_mode); +void BubbleViewModeFromAvatarBubbleMode(BrowserWindow::AvatarBubbleMode mode, + BubbleViewMode* bubble_view_mode); } // namespace profiles
diff --git a/chrome/browser/profiles/profile_window_browsertest.cc b/chrome/browser/profiles/profile_window_browsertest.cc index 099624e1..31ecb86 100644 --- a/chrome/browser/profiles/profile_window_browsertest.cc +++ b/chrome/browser/profiles/profile_window_browsertest.cc
@@ -257,7 +257,6 @@ base::RunLoop run_loop; profiles::CreateSystemProfileForUserManager( browser()->profile()->GetPath(), - profiles::USER_MANAGER_NO_TUTORIAL, profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION, base::Bind(&ProfileWindowWebUIBrowserTest::OnSystemProfileCreated, base::Unretained(this), @@ -281,7 +280,6 @@ base::RunLoop run_loop; profiles::CreateSystemProfileForUserManager( expected_path, - profiles::USER_MANAGER_NO_TUTORIAL, profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION, base::Bind(&ProfileWindowWebUIBrowserTest::OnSystemProfileCreated, base::Unretained(this),
diff --git a/chrome/browser/resources/bluetooth_internals/expandable_list.js b/chrome/browser/resources/bluetooth_internals/expandable_list.js index 5f543e68..8f172561e 100644 --- a/chrome/browser/resources/bluetooth_internals/expandable_list.js +++ b/chrome/browser/resources/bluetooth_internals/expandable_list.js
@@ -137,5 +137,5 @@ return { ExpandableListItem: ExpandableListItem, ExpandableList: ExpandableList, - } + }; }); \ No newline at end of file
diff --git a/chrome/browser/resources/bluetooth_internals/value_control.js b/chrome/browser/resources/bluetooth_internals/value_control.js index bd5673f..9146e59 100644 --- a/chrome/browser/resources/bluetooth_internals/value_control.js +++ b/chrome/browser/resources/bluetooth_internals/value_control.js
@@ -400,7 +400,7 @@ 'Retry', this.writeValue_.bind(this)); }.bind(this)); }, - } + }; return { ValueControl: ValueControl,
diff --git a/chrome/browser/resources/bookmark_manager/js/main.js b/chrome/browser/resources/bookmark_manager/js/main.js index ad2568bd..c2689e21 100644 --- a/chrome/browser/resources/bookmark_manager/js/main.js +++ b/chrome/browser/resources/bookmark_manager/js/main.js
@@ -883,7 +883,7 @@ */ function getSelectedBookmarkIds(opt_target) { var selectedNodes = getSelectedBookmarkNodes(opt_target); - selectedNodes.sort(function(a, b) { return a.index - b.index }); + selectedNodes.sort(function(a, b) { return a.index - b.index; }); return selectedNodes.map(function(node) { return node.id; });
diff --git a/chrome/browser/resources/chromeos/chromevox/braille/braille_table.js b/chrome/browser/resources/chromeos/chromevox/braille/braille_table.js index 8957d1c2..2098b86d 100644 --- a/chrome/browser/resources/chromeos/chromevox/braille/braille_table.js +++ b/chrome/browser/resources/chromeos/chromevox/braille/braille_table.js
@@ -76,7 +76,7 @@ * @return {cvox.BrailleTable.Table} The found table, or null if not found. */ cvox.BrailleTable.forId = function(tables, id) { - return tables.filter(function(table) { return table.id === id })[0] || null; + return tables.filter(function(table) { return table.id === id; })[0] || null; };
diff --git a/chrome/browser/resources/chromeos/chromevox/braille/expanding_braille_translator.js b/chrome/browser/resources/chromeos/chromevox/braille/expanding_braille_translator.js index 0a8bdfb..563f8e139 100644 --- a/chrome/browser/resources/chromeos/chromevox/braille/expanding_braille_translator.js +++ b/chrome/browser/resources/chromeos/chromevox/braille/expanding_braille_translator.js
@@ -152,7 +152,7 @@ function finish() { var totalCells = chunks.reduce( - function(accum, chunk) { return accum + chunk.cells.byteLength}, 0); + function(accum, chunk) { return accum + chunk.cells.byteLength;}, 0); var cells = new Uint8Array(totalCells); var cellPos = 0; var textToBraille = [];
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/injected/event_suspender.js b/chrome/browser/resources/chromeos/chromevox/chromevox/injected/event_suspender.js index 2cd7865..73b2ba4 100644 --- a/chrome/browser/resources/chromeos/chromevox/chromevox/injected/event_suspender.js +++ b/chrome/browser/resources/chromeos/chromevox/chromevox/injected/event_suspender.js
@@ -27,14 +27,14 @@ */ cvox.ChromeVoxEventSuspender.enterSuspendEvents = function() { cvox.ChromeVoxEventSuspender.suspendLevel_ += 1; -} +}; /** * Exits a (nested) suspended state. */ cvox.ChromeVoxEventSuspender.exitSuspendEvents = function() { cvox.ChromeVoxEventSuspender.suspendLevel_ -= 1; -} +}; /** * Returns true if events are currently suspended.
diff --git a/chrome/browser/resources/chromeos/chromevox/common/media_widget.js b/chrome/browser/resources/chromeos/chromevox/common/media_widget.js index 7b6dd05..0c2444cb 100644 --- a/chrome/browser/resources/chromeos/chromevox/common/media_widget.js +++ b/chrome/browser/resources/chromeos/chromevox/common/media_widget.js
@@ -25,10 +25,10 @@ this.keyListener_ = function(evt) { self.eventHandler_(evt); - } + }; this.blurListener_ = function(evt) { self.shutdown(); - } + }; this.mediaElem_.addEventListener('keydown', this.keyListener_, false); this.mediaElem_.addEventListener('keyup', this.keyListener_, false);
diff --git a/chrome/browser/resources/chromeos/chromevox/common/spannable.js b/chrome/browser/resources/chromeos/chromevox/common/spannable.js index 64c9656..a275621 100644 --- a/chrome/browser/resources/chromeos/chromevox/common/spannable.js +++ b/chrome/browser/resources/chromeos/chromevox/common/spannable.js
@@ -428,7 +428,7 @@ function spanInstanceOf(constructor) { return function(span) { return span.value instanceof constructor; - } + }; } /** @@ -438,7 +438,7 @@ function spanCoversPosition(position) { return function(span) { return span.start <= position && position < span.end; - } + }; } /** @@ -448,7 +448,7 @@ function spanValueIs(value) { return function(span) { return span.value === value; - } + }; } /**
diff --git a/chrome/browser/resources/chromeos/chromevox/testing/callback_helper.js b/chrome/browser/resources/chromeos/chromevox/testing/callback_helper.js index 6f14d2f..a671637 100644 --- a/chrome/browser/resources/chromeos/chromevox/testing/callback_helper.js +++ b/chrome/browser/resources/chromeos/chromevox/testing/callback_helper.js
@@ -40,7 +40,7 @@ return function() { savedArgs.arguments = Array.prototype.slice.call(arguments); runAll.invoke(); - } + }; } };
diff --git a/chrome/browser/resources/chromeos/login/login_shared.js b/chrome/browser/resources/chromeos/login/login_shared.js index 9e21431..e073b61e 100644 --- a/chrome/browser/resources/chromeos/login/login_shared.js +++ b/chrome/browser/resources/chromeos/login/login_shared.js
@@ -474,5 +474,5 @@ // Install a global error handler so stack traces are included in logs. window.onerror = function(message, file, line, column, error) { console.error(error.stack); - } + }; })();
diff --git a/chrome/browser/resources/chromeos/login/md_login_shared.js b/chrome/browser/resources/chromeos/login/md_login_shared.js index b4b78f8..41afbaa 100644 --- a/chrome/browser/resources/chromeos/login/md_login_shared.js +++ b/chrome/browser/resources/chromeos/login/md_login_shared.js
@@ -474,5 +474,5 @@ // Install a global error handler so stack traces are included in logs. window.onerror = function(message, file, line, column, error) { console.error(error.stack); - } + }; })();
diff --git a/chrome/browser/resources/chromeos/login/oobe.js b/chrome/browser/resources/chromeos/login/oobe.js index d25ad7e68..14962b8 100644 --- a/chrome/browser/resources/chromeos/login/oobe.js +++ b/chrome/browser/resources/chromeos/login/oobe.js
@@ -239,7 +239,7 @@ return; // Simulate click on the checkbox. - e.target.click() + e.target.click(); }, /**
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js b/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js index 2ff4fa3..183abf4 100644 --- a/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js +++ b/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js
@@ -51,7 +51,7 @@ */ isCancelDisabled_: null, - get isCancelDisabled() { return this.isCancelDisabled_ }, + get isCancelDisabled() { return this.isCancelDisabled_; }, set isCancelDisabled(disabled) { this.isCancelDisabled_ = disabled; },
diff --git a/chrome/browser/resources/chromeos/login/oobe_welcome.js b/chrome/browser/resources/chromeos/login/oobe_welcome.js index aeaba1a..cd1ec9f 100644 --- a/chrome/browser/resources/chromeos/login/oobe_welcome.js +++ b/chrome/browser/resources/chromeos/login/oobe_welcome.js
@@ -139,7 +139,7 @@ hideAllScreens_: function() { this.$.welcomeScreen.hidden = true; - var screens = Polymer.dom(this.root).querySelectorAll('oobe-dialog') + var screens = Polymer.dom(this.root).querySelectorAll('oobe-dialog'); for (var i = 0; i < screens.length; ++i) { screens[i].hidden = true; } @@ -164,7 +164,7 @@ * @private */ getActiveScreen_: function() { - var screens = Polymer.dom(this.root).querySelectorAll('oobe-dialog') + var screens = Polymer.dom(this.root).querySelectorAll('oobe-dialog'); for (var i = 0; i < screens.length; ++i) { if (!screens[i].hidden) return screens[i];
diff --git a/chrome/browser/resources/chromeos/power.js b/chrome/browser/resources/chromeos/power.js index 98c38de..41a6e710 100644 --- a/chrome/browser/resources/chromeos/power.js +++ b/chrome/browser/resources/chromeos/power.js
@@ -836,7 +836,7 @@ $(sectionId).hidden = true; $(buttonId).textContent = loadTimeData.getString('showButton'); } - } + }; } var powerUI = {
diff --git a/chrome/browser/resources/chromeos/switch_access/automation_predicate.js b/chrome/browser/resources/chromeos/switch_access/automation_predicate.js index 756839f..195ebafd 100644 --- a/chrome/browser/resources/chromeos/switch_access/automation_predicate.js +++ b/chrome/browser/resources/chromeos/switch_access/automation_predicate.js
@@ -122,4 +122,4 @@ // The general rule that applies to everything. return state[chrome.automation.StateType.FOCUSABLE] === true; -} +};
diff --git a/chrome/browser/resources/cleanup_tool/cleanup_browser_proxy.js b/chrome/browser/resources/cleanup_tool/cleanup_browser_proxy.js index ef22211..e9c463d 100644 --- a/chrome/browser/resources/cleanup_tool/cleanup_browser_proxy.js +++ b/chrome/browser/resources/cleanup_tool/cleanup_browser_proxy.js
@@ -74,5 +74,5 @@ return { CleanupBrowserProxy: CleanupBrowserProxy, CleanupBrowserProxyImpl: CleanupBrowserProxyImpl, - } + }; });
diff --git a/chrome/browser/resources/cryptotoken/gnubbies.js b/chrome/browser/resources/cryptotoken/gnubbies.js index 8424b39..cbb92cb 100644 --- a/chrome/browser/resources/cryptotoken/gnubbies.js +++ b/chrome/browser/resources/cryptotoken/gnubbies.js
@@ -213,7 +213,7 @@ function makeEnumerateCb(namespace) { return function(devs) { enumerated(namespace, deviceIds, devs); - } + }; } this.pendingEnumerate.push(cb);
diff --git a/chrome/browser/resources/inspect/inspect.js b/chrome/browser/resources/inspect/inspect.js index c770ab9..512552b7 100644 --- a/chrome/browser/resources/inspect/inspect.js +++ b/chrome/browser/resources/inspect/inspect.js
@@ -225,7 +225,7 @@ section.remove(); } - var newDeviceIds = devices.map(function(d) { return d.id }); + var newDeviceIds = devices.map(function(d) { return d.id; }); Array.prototype.forEach.call( deviceList.querySelectorAll('.device'), removeObsolete.bind(null, newDeviceIds)); @@ -282,7 +282,7 @@ var browserList = deviceSection.querySelector('.browsers'); var newBrowserIds = - device.browsers.map(function(b) { return b.id }); + device.browsers.map(function(b) { return b.id; }); Array.prototype.forEach.call( browserList.querySelectorAll('.browser'), removeObsolete.bind(null, newBrowserIds));
diff --git a/chrome/browser/resources/md_bookmarks/dnd_manager.js b/chrome/browser/resources/md_bookmarks/dnd_manager.js index c5c3c7e..a4423b3 100644 --- a/chrome/browser/resources/md_bookmarks/dnd_manager.js +++ b/chrome/browser/resources/md_bookmarks/dnd_manager.js
@@ -626,7 +626,7 @@ if (getBookmarkNode(overElement).url) return false; - return !this.dragInfo_.isDraggingChildBookmark(overElement.itemId) + return !this.dragInfo_.isDraggingChildBookmark(overElement.itemId); }, disableTimeoutsForTesting: function() {
diff --git a/chrome/browser/resources/net_internals/modules_view.js b/chrome/browser/resources/net_internals/modules_view.js index dbb0b9c..f02a53d 100644 --- a/chrome/browser/resources/net_internals/modules_view.js +++ b/chrome/browser/resources/net_internals/modules_view.js
@@ -107,7 +107,7 @@ ModulesView.getLayeredServiceProviderProtocolType = function(serviceProvider) { return tryGetValueWithKey(PROTOCOL_TYPE, serviceProvider.socket_protocol); - } + }; var NAMESPACE_PROVIDER_PTYPE = { '12': 'NS_DNS',
diff --git a/chrome/browser/resources/sync_file_system_internals/dump_database.js b/chrome/browser/resources/sync_file_system_internals/dump_database.js index 58025bc..1f0b9f27 100644 --- a/chrome/browser/resources/sync_file_system_internals/dump_database.js +++ b/chrome/browser/resources/sync_file_system_internals/dump_database.js
@@ -78,7 +78,7 @@ div.appendChild(table); placeholder.appendChild(div); } -} +}; function main() { getDatabaseDump();
diff --git a/chrome/browser/resources/sync_file_system_internals/extension_statuses.js b/chrome/browser/resources/sync_file_system_internals/extension_statuses.js index a31de23..0b805ae 100644 --- a/chrome/browser/resources/sync_file_system_internals/extension_statuses.js +++ b/chrome/browser/resources/sync_file_system_internals/extension_statuses.js
@@ -48,7 +48,7 @@ tr.appendChild(createElementFromText('td', originEntry.status)); itemContainer.appendChild(tr); } -} +}; function main() { getExtensionStatuses();
diff --git a/chrome/browser/resources/sync_file_system_internals/sync_service.js b/chrome/browser/resources/sync_file_system_internals/sync_service.js index b5a2578..299abc57 100644 --- a/chrome/browser/resources/sync_file_system_internals/sync_service.js +++ b/chrome/browser/resources/sync_file_system_internals/sync_service.js
@@ -23,7 +23,7 @@ */ SyncService.onGetServiceStatus = function(statusString) { $('service-status').textContent = statusString; -} +}; /** * Request Google Drive Notification Source. e.g. XMPP or polling. @@ -38,7 +38,7 @@ */ SyncService.onGetNotificationSource = function(sourceString) { $('notification-source').textContent = sourceString; -} +}; // Keeps track of the last log event seen so it's not reprinted. var lastLogEventId = -1; @@ -76,7 +76,7 @@ lastLogEventId = logEntry.id; } -} +}; /** * Get initial sync service values and set listeners to get updated values.
diff --git a/chrome/browser/resources/sync_file_system_internals/task_log.js b/chrome/browser/resources/sync_file_system_internals/task_log.js index 0cc24db3..5379754 100644 --- a/chrome/browser/resources/sync_file_system_internals/task_log.js +++ b/chrome/browser/resources/sync_file_system_internals/task_log.js
@@ -44,7 +44,7 @@ tr.appendChild(details); $('task-log-entries').appendChild(tr); -} +}; /** * Get initial sync service values and set listeners to get updated values.
diff --git a/chrome/browser/signin/chrome_signin_client.cc b/chrome/browser/signin/chrome_signin_client.cc index ccf25e0..77e10c2 100644 --- a/chrome/browser/signin/chrome_signin_client.cc +++ b/chrome/browser/signin/chrome_signin_client.cc
@@ -474,7 +474,7 @@ void ChromeSigninClient::ShowUserManager(const base::FilePath& profile_path) { #if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) - UserManager::Show(profile_path, profiles::USER_MANAGER_NO_TUTORIAL, + UserManager::Show(profile_path, profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); #endif }
diff --git a/chrome/browser/ui/app_list/app_list_service_disabled.cc b/chrome/browser/ui/app_list/app_list_service_disabled.cc index a2ffa9a..9090317 100644 --- a/chrome/browser/ui/app_list/app_list_service_disabled.cc +++ b/chrome/browser/ui/app_list/app_list_service_disabled.cc
@@ -97,7 +97,7 @@ if (IsProfileSignedOut(app_list_profile) || app_list_profile->IsSystemProfile() || app_list_profile->IsGuestSession()) { - UserManager::Show(base::FilePath(), profiles::USER_MANAGER_NO_TUTORIAL, + UserManager::Show(base::FilePath(), profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); return; }
diff --git a/chrome/browser/ui/app_list/profile_loader.cc b/chrome/browser/ui/app_list/profile_loader.cc index be09089c..21d6bf408 100644 --- a/chrome/browser/ui/app_list/profile_loader.cc +++ b/chrome/browser/ui/app_list/profile_loader.cc
@@ -36,7 +36,6 @@ if (profile_store_->IsProfileLocked(profile_file_path)) { UserManager::Show(base::FilePath(), - profiles::USER_MANAGER_NO_TUTORIAL, profiles::USER_MANAGER_SELECT_PROFILE_APP_LAUNCHER); return; }
diff --git a/chrome/browser/ui/app_list/search_answer_web_contents_delegate.cc b/chrome/browser/ui/app_list/search_answer_web_contents_delegate.cc index d9ba2e56..a0f9487b 100644 --- a/chrome/browser/ui/app_list/search_answer_web_contents_delegate.cc +++ b/chrome/browser/ui/app_list/search_answer_web_contents_delegate.cc
@@ -21,6 +21,7 @@ #include "ui/app_list/app_list_features.h" #include "ui/app_list/app_list_model.h" #include "ui/app_list/search_box_model.h" +#include "ui/views/controls/webview/web_contents_set_background_color.h" #include "ui/views/controls/webview/webview.h" #include "ui/views/widget/widget.h" @@ -105,6 +106,11 @@ web_view_->SetFocusBehavior(views::View::FocusBehavior::NEVER); model->AddObserver(this); + + // Make the webview transparent since it's going to be shown on top of a + // highlightable button. + views::WebContentsSetBackgroundColor::CreateForWebContentsWithColor( + web_contents_.get(), SK_ColorTRANSPARENT); } SearchAnswerWebContentsDelegate::~SearchAnswerWebContentsDelegate() { @@ -168,8 +174,7 @@ IsCardSizeOk(pref_size) || features::IsAnswerCardDarkRunEnabled(); model_->SetSearchAnswerAvailable(is_card_size_ok_ && received_answer_ && !web_contents_->IsLoading()); - if (!features::IsAnswerCardDarkRunEnabled()) - web_view_->SetPreferredSize(pref_size); + web_view_->SetPreferredSize(pref_size); if (!answer_loaded_time_.is_null()) { UMA_HISTOGRAM_TIMES("SearchAnswer.ResizeAfterLoadTime", base::TimeTicks::Now() - answer_loaded_time_);
diff --git a/chrome/browser/ui/ash/shelf_browsertest.cc b/chrome/browser/ui/ash/shelf_browsertest.cc index 6a72221c..022c90b 100644 --- a/chrome/browser/ui/ash/shelf_browsertest.cc +++ b/chrome/browser/ui/ash/shelf_browsertest.cc
@@ -4,7 +4,6 @@ #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_layout_manager.h" -#include "ash/wm_window.h" #include "base/command_line.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm index cb61d3a..0416c62d 100644 --- a/chrome/browser/ui/cocoa/browser_window_cocoa.mm +++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -821,9 +821,7 @@ signin_metrics::AccessPoint access_point, bool is_source_keyboard) { profiles::BubbleViewMode bubble_view_mode; - profiles::TutorialMode tutorial_mode; - profiles::BubbleViewModeFromAvatarBubbleMode(mode, &bubble_view_mode, - &tutorial_mode); + profiles::BubbleViewModeFromAvatarBubbleMode(mode, &bubble_view_mode); if (SigninViewController::ShouldShowModalSigninForMode(bubble_view_mode)) { browser_->signin_view_controller()->ShowModalSignin(bubble_view_mode,
diff --git a/chrome/browser/ui/cocoa/extensions/extension_message_bubble_browsertest_mac.mm b/chrome/browser/ui/cocoa/extensions/extension_message_bubble_browsertest_mac.mm index 94457df..b8a3d02 100644 --- a/chrome/browser/ui/cocoa/extensions/extension_message_bubble_browsertest_mac.mm +++ b/chrome/browser/ui/cocoa/extensions/extension_message_bubble_browsertest_mac.mm
@@ -105,17 +105,6 @@ DISALLOW_COPY_AND_ASSIGN(ExtensionMessageBubbleBrowserTestMac); }; -class ExtensionMessageBubbleBrowserTestLegacyMac - : public ExtensionMessageBubbleBrowserTestMac { - protected: - void SetUpCommandLine(base::CommandLine* command_line) override { - ExtensionMessageBubbleBrowserTestMac::SetUpCommandLine(command_line); - override_redesign_.reset(); - override_redesign_.reset(new extensions::FeatureSwitch::ScopedOverride( - extensions::FeatureSwitch::extension_action_redesign(), false)); - } -}; - void ExtensionMessageBubbleBrowserTestMac::SetUpCommandLine( base::CommandLine* command_line) { ExtensionMessageBubbleBrowserTest::SetUpCommandLine(command_line); @@ -180,12 +169,12 @@ TestBubbleAnchoredToExtensionAction(); } -IN_PROC_BROWSER_TEST_F(ExtensionMessageBubbleBrowserTestLegacyMac, +IN_PROC_BROWSER_TEST_F(ExtensionMessageBubbleBrowserTestMac, ExtensionBubbleAnchoredToAppMenu) { TestBubbleAnchoredToAppMenu(); } -IN_PROC_BROWSER_TEST_F(ExtensionMessageBubbleBrowserTestLegacyMac, +IN_PROC_BROWSER_TEST_F(ExtensionMessageBubbleBrowserTestMac, ExtensionBubbleAnchoredToAppMenuWithOtherAction) { TestBubbleAnchoredToAppMenuWithOtherAction(); }
diff --git a/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm b/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm index a3e0d5a1..190db7a 100644 --- a/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm +++ b/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm
@@ -133,14 +133,11 @@ fromAccessPoint:(signin_metrics::AccessPoint)accessPoint { if (menuController_) { profiles::BubbleViewMode viewMode; - profiles::TutorialMode tutorialMode; - profiles::BubbleViewModeFromAvatarBubbleMode( - mode, &viewMode, &tutorialMode); - if (tutorialMode != profiles::TUTORIAL_MODE_NONE) { + profiles::BubbleViewModeFromAvatarBubbleMode(mode, &viewMode); + if (viewMode == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER) { ProfileChooserController* profileChooserController = base::mac::ObjCCastStrict<ProfileChooserController>( menuController_); - [profileChooserController setTutorialMode:tutorialMode]; [profileChooserController initMenuContentsWithView:viewMode]; } return; @@ -168,15 +165,12 @@ // |menuController_| will automatically release itself on close. profiles::BubbleViewMode viewMode; - profiles::TutorialMode tutorialMode; - profiles::BubbleViewModeFromAvatarBubbleMode( - mode, &viewMode, &tutorialMode); + profiles::BubbleViewModeFromAvatarBubbleMode(mode, &viewMode); menuController_ = [[ProfileChooserController alloc] initWithBrowser:browser_ anchoredAt:point viewMode:viewMode - tutorialMode:tutorialMode serviceType:serviceType accessPoint:accessPoint];
diff --git a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.h b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.h index c706514..623fdce 100644 --- a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.h +++ b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.h
@@ -53,9 +53,6 @@ // Active view mode. profiles::BubbleViewMode viewMode_; - // The current tutorial mode. - profiles::TutorialMode tutorialMode_; - // List of the full, un-elided accounts for the active profile. The keys are // generated used to tag the UI buttons, and the values are the original // emails displayed by the buttons. @@ -78,7 +75,6 @@ - (id)initWithBrowser:(Browser*)browser anchoredAt:(NSPoint)point viewMode:(profiles::BubbleViewMode)viewMode - tutorialMode:(profiles::TutorialMode)tutorialMode serviceType:(signin::GAIAServiceType)GAIAServiceType accessPoint:(signin_metrics::AccessPoint)accessPoint; @@ -88,9 +84,6 @@ // Returns the view currently displayed by the bubble. - (profiles::BubbleViewMode)viewMode; -// Sets the tutorial mode of the bubble. -- (void)setTutorialMode:(profiles::TutorialMode)tutorialMode; - // Switches to a given profile. |sender| is an ProfileChooserItemController. - (IBAction)switchToProfile:(id)sender; @@ -139,9 +132,7 @@ - (id)initWithBrowser:(Browser*)browser anchoredAt:(NSPoint)point viewMode:(profiles::BubbleViewMode)viewMode - tutorialMode:(profiles::TutorialMode)tutorialMode serviceType:(signin::GAIAServiceType)GAIAServiceType; -- (IBAction)dismissTutorial:(id)sender; @end #endif // CHROME_BROWSER_UI_COCOA_PROFILES_PROFILE_CHOOSER_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm index 4c54c885..462bca4 100644 --- a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm +++ b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm
@@ -676,7 +676,6 @@ // Builds the regular profile chooser view. - (void)buildProfileChooserViewWithProfileView:(NSView*)currentProfileView - tutorialView:(NSView*)tutorialView syncErrorView:(NSView*)syncErrorView otherProfiles:(NSArray*)otherProfiles atYOffset:(CGFloat)yOffset @@ -686,38 +685,9 @@ // Builds the profile chooser view. - (NSView*)buildProfileChooserView; -// Builds a tutorial card with a title label using |titleMessage|, a content -// label using |contentMessage|, a link using |linkMessage|, and a button using -// |buttonMessage|. If |stackButton| is YES, places the button above the link. -// Otherwise places both on the same row with the link left aligned and button -// right aligned. On click, the link would execute |linkAction|, and the button -// would execute |buttonAction|. It sets |tutorialMode_| to the given |mode|. -- (NSView*)tutorialViewWithMode:(profiles::TutorialMode)mode - titleMessage:(NSString*)titleMessage - contentMessage:(NSString*)contentMessage - linkMessage:(NSString*)linkMessage - buttonMessage:(NSString*)buttonMessage - stackButton:(BOOL)stackButton - hasCloseButton:(BOOL)hasCloseButton - linkAction:(SEL)linkAction - buttonAction:(SEL)buttonAction; - // Builds a header for signin and sync error surfacing on the user menu. - (NSView*)buildSyncErrorViewIfNeeded; -// Builds a tutorial card to introduce an upgrade user to the new avatar menu if -// needed. |tutorial_shown| indicates if the tutorial has already been shown in -// the previous active view. |avatar_item| refers to the current profile. -- (NSView*)buildWelcomeUpgradeTutorialView:(const AvatarMenu::Item&)item; - -// Builds a tutorial card to have the user confirm the last Chrome signin, -// Chrome sync will be delayed until the user either dismisses the tutorial, or -// configures sync through the "Settings" link. -- (NSView*)buildSigninConfirmationView; - -// Builds a tutorial card to show the last signin error. -- (NSView*)buildSigninErrorView; - // Creates the main profile card for the profile |item| at the top of // the bubble. - (NSView*)createCurrentProfileView:(const AvatarMenu::Item&)item; @@ -793,10 +763,6 @@ return viewMode_; } -- (void)setTutorialMode:(profiles::TutorialMode)tutorialMode { - tutorialMode_ = tutorialMode; -} - - (IBAction)editProfile:(id)sender { avatarMenu_->EditProfile(avatarMenu_->GetActiveProfileIndex()); [self postActionPerformed:ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_IMAGE]; @@ -821,7 +787,6 @@ - (IBAction)showUserManager:(id)sender { UserManager::Show(base::FilePath(), - profiles::USER_MANAGER_NO_TUTORIAL, profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); [self postActionPerformed: ProfileMetrics::PROFILE_DESKTOP_MENU_OPEN_USER_MANAGER]; @@ -830,7 +795,6 @@ - (IBAction)exitGuest:(id)sender { DCHECK(browser_->profile()->IsGuestSession()); UserManager::Show(base::FilePath(), - profiles::USER_MANAGER_NO_TUTORIAL, profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); profiles::CloseGuestProfileWindows(); } @@ -941,14 +905,6 @@ [self initMenuContentsWithView:profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT]; } -- (IBAction)seeWhatsNew:(id)sender { - UserManager::Show(base::FilePath(), - profiles::USER_MANAGER_TUTORIAL_OVERVIEW, - profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); - ProfileMetrics::LogProfileNewAvatarMenuUpgrade( - ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_WHATS_NEW); -} - - (IBAction)showSwitchUserView:(id)sender { [self initMenuContentsWithView:profiles::BUBBLE_VIEW_MODE_SWITCH_USER]; ProfileMetrics::LogProfileNewAvatarMenuUpgrade( @@ -960,7 +916,6 @@ } - (IBAction)configureSyncSettings:(id)sender { - tutorialMode_ = profiles::TUTORIAL_MODE_NONE; LoginUIServiceFactory::GetForProfile(browser_->profile())-> SyncConfirmationUIClosed(LoginUIService::CONFIGURE_SYNC_FIRST); ProfileMetrics::LogProfileNewAvatarMenuSignin( @@ -968,7 +923,6 @@ } - (IBAction)syncSettingsConfirmed:(id)sender { - tutorialMode_ = profiles::TUTORIAL_MODE_NONE; LoginUIServiceFactory::GetForProfile(browser_->profile())-> SyncConfirmationUIClosed(LoginUIService::SYNC_WITH_DEFAULT_SETTINGS); ProfileMetrics::LogProfileNewAvatarMenuSignin( @@ -988,24 +942,7 @@ ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_BACK); } -- (IBAction)dismissTutorial:(id)sender { - // Never shows the upgrade tutorial again if manually closed. - if (tutorialMode_ == profiles::TUTORIAL_MODE_WELCOME_UPGRADE) { - browser_->profile()->GetPrefs()->SetInteger( - prefs::kProfileAvatarTutorialShown, - signin_ui_util::kUpgradeWelcomeTutorialShowMax + 1); - } - - tutorialMode_ = profiles::TUTORIAL_MODE_NONE; - [self initMenuContentsWithView:profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER]; -} - - (void)windowWillClose:(NSNotification*)notification { - if (tutorialMode_ == profiles::TUTORIAL_MODE_CONFIRM_SIGNIN) { - LoginUIServiceFactory::GetForProfile(browser_->profile())-> - SyncConfirmationUIClosed(LoginUIService::SYNC_WITH_DEFAULT_SETTINGS); - } - [super windowWillClose:notification]; } @@ -1025,7 +962,6 @@ - (id)initWithBrowser:(Browser*)browser anchoredAt:(NSPoint)point viewMode:(profiles::BubbleViewMode)viewMode - tutorialMode:(profiles::TutorialMode)tutorialMode serviceType:(signin::GAIAServiceType)serviceType accessPoint:(signin_metrics::AccessPoint)accessPoint { base::scoped_nsobject<InfoBubbleWindow> window([[InfoBubbleWindow alloc] @@ -1039,7 +975,6 @@ anchoredAt:point])) { browser_ = browser; viewMode_ = viewMode; - tutorialMode_ = tutorialMode; observer_.reset(new ActiveProfileObserverBridge(self, browser_)); serviceType_ = serviceType; accessPoint_ = accessPoint; @@ -1114,10 +1049,6 @@ break; } - // Clears tutorial mode for all non-profile-chooser views. - if (viewMode_ != profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER) - tutorialMode_ = profiles::TUTORIAL_MODE_NONE; - // Add a dummy, empty element so that we don't initially display any // focus rings. NSButton* dummyFocusButton = @@ -1158,7 +1089,6 @@ } - (void)buildProfileChooserViewWithProfileView:(NSView*)currentProfileView - tutorialView:(NSView*)tutorialView syncErrorView:(NSView*)syncErrorView otherProfiles:(NSArray*)otherProfiles atYOffset:(CGFloat)yOffset @@ -1229,15 +1159,6 @@ yOffset = NSMaxY([syncErrorView frame]); } - if (tutorialView) { - [tutorialView setFrameOrigin:NSMakePoint(0, yOffset)]; - [container addSubview:tutorialView]; - yOffset = NSMaxY([tutorialView frame]); - //TODO(mlerman): update UMA stats for the new tutorials. - } else { - tutorialMode_ = profiles::TUTORIAL_MODE_NONE; - } - [container setFrameSize:NSMakeSize(kFixedMenuWidth, yOffset)]; } @@ -1245,7 +1166,6 @@ base::scoped_nsobject<NSView> container( [[NSView alloc] initWithFrame:NSZeroRect]); - NSView* tutorialView = nil; NSView* syncErrorView = nil; NSView* currentProfileView = nil; base::scoped_nsobject<NSMutableArray> otherProfiles( @@ -1276,7 +1196,6 @@ CGFloat yOffset = 1; [self buildProfileChooserViewWithProfileView:currentProfileView - tutorialView:tutorialView syncErrorView:syncErrorView otherProfiles:otherProfiles.get() atYOffset:yOffset @@ -1285,216 +1204,6 @@ return container.autorelease(); } -- (NSView*)buildSigninConfirmationView { - ProfileMetrics::LogProfileNewAvatarMenuSignin( - ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_VIEW); - - NSString* titleMessage = l10n_util::GetNSString( - IDS_PROFILES_CONFIRM_SIGNIN_TUTORIAL_TITLE); - NSString* contentMessage = l10n_util::GetNSString( - IDS_PROFILES_CONFIRM_SIGNIN_TUTORIAL_CONTENT_TEXT); - NSString* linkMessage = l10n_util::GetNSString( - IDS_PROFILES_SYNC_SETTINGS_LINK); - NSString* buttonMessage = l10n_util::GetNSString( - IDS_PROFILES_TUTORIAL_OK_BUTTON); - return [self tutorialViewWithMode:profiles::TUTORIAL_MODE_CONFIRM_SIGNIN - titleMessage:titleMessage - contentMessage:contentMessage - linkMessage:linkMessage - buttonMessage:buttonMessage - stackButton:NO - hasCloseButton:NO - linkAction:@selector(configureSyncSettings:) - buttonAction:@selector(syncSettingsConfirmed:)]; -} - -- (NSView*)buildSigninErrorView { - NSString* titleMessage = l10n_util::GetNSString( - IDS_PROFILES_ERROR_TUTORIAL_TITLE); - LoginUIService* loginUiService = - LoginUIServiceFactory::GetForProfile(browser_->profile()); - NSString* contentMessage = - base::SysUTF16ToNSString(loginUiService->GetLastLoginResult()); - NSString* linkMessage = l10n_util::GetNSString( - IDS_PROFILES_PROFILE_TUTORIAL_LEARN_MORE); - return [self tutorialViewWithMode:profiles::TUTORIAL_MODE_CONFIRM_SIGNIN - titleMessage:titleMessage - contentMessage:contentMessage - linkMessage:linkMessage - buttonMessage:nil - stackButton:NO - hasCloseButton:YES - linkAction:@selector(showLearnMorePage:) - buttonAction:nil]; -} - -- (NSView*)buildWelcomeUpgradeTutorialView:(const AvatarMenu::Item&)item { - ProfileMetrics::LogProfileNewAvatarMenuUpgrade( - ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_VIEW); - - NSString* titleMessage = l10n_util::GetNSString( - IDS_PROFILES_WELCOME_UPGRADE_TUTORIAL_TITLE); - NSString* contentMessage = l10n_util::GetNSString( - IDS_PROFILES_WELCOME_UPGRADE_TUTORIAL_CONTENT_TEXT); - // For local profiles, the "Not you" link doesn't make sense. - NSString* linkMessage = - item.signed_in ? ElideMessage(l10n_util::GetStringFUTF16( - IDS_PROFILES_NOT_YOU, item.name), - kFixedMenuWidth - 2 * kHorizontalSpacing) - : nil; - NSString* buttonMessage = l10n_util::GetNSString( - IDS_PROFILES_TUTORIAL_WHATS_NEW_BUTTON); - return [self tutorialViewWithMode:profiles::TUTORIAL_MODE_WELCOME_UPGRADE - titleMessage:titleMessage - contentMessage:contentMessage - linkMessage:linkMessage - buttonMessage:buttonMessage - stackButton:YES - hasCloseButton:YES - linkAction:@selector(showSwitchUserView:) - buttonAction:@selector(seeWhatsNew:)]; -} - -- (NSView*)tutorialViewWithMode:(profiles::TutorialMode)mode - titleMessage:(NSString*)titleMessage - contentMessage:(NSString*)contentMessage - linkMessage:(NSString*)linkMessage - buttonMessage:(NSString*)buttonMessage - stackButton:(BOOL)stackButton - hasCloseButton:(BOOL)hasCloseButton - linkAction:(SEL)linkAction - buttonAction:(SEL)buttonAction { - tutorialMode_ = mode; - - NSColor* tutorialBackgroundColor = - skia::SkColorToSRGBNSColor(profiles::kAvatarTutorialBackgroundColor); - base::scoped_nsobject<NSView> container([[BackgroundColorView alloc] - initWithFrame:NSMakeRect(0, 0, kFixedMenuWidth, 0) - withColor:tutorialBackgroundColor]); - CGFloat availableWidth = kFixedMenuWidth - 2 * kHorizontalSpacing; - CGFloat yOffset = kVerticalSpacing; - - // Adds links and buttons at the bottom. - base::scoped_nsobject<NSButton> tutorialOkButton; - if (buttonMessage) { - tutorialOkButton.reset([[HoverButton alloc] initWithFrame:NSZeroRect]); - [tutorialOkButton setTitle:buttonMessage]; - [tutorialOkButton setBezelStyle:NSRoundedBezelStyle]; - [tutorialOkButton setTarget:self]; - [tutorialOkButton setAction:buttonAction]; - [tutorialOkButton setAlignment:NSCenterTextAlignment]; - [tutorialOkButton sizeToFit]; - } - - NSButton* learnMoreLink = nil; - if (linkMessage) { - learnMoreLink = [self linkButtonWithTitle:linkMessage - frameOrigin:NSZeroPoint - action:linkAction]; - [[learnMoreLink cell] setTextColor:[NSColor whiteColor]]; - } - - if (stackButton) { - [learnMoreLink setFrameOrigin:NSMakePoint((kFixedMenuWidth - - NSWidth([learnMoreLink frame])) / - 2, - yOffset)]; - [tutorialOkButton setFrameSize:NSMakeSize( - availableWidth, NSHeight([tutorialOkButton frame]))]; - [tutorialOkButton setFrameOrigin:NSMakePoint( - kHorizontalSpacing, - yOffset + (learnMoreLink ? NSHeight([learnMoreLink frame]) : 0))]; - } else { - if (buttonMessage) { - NSSize buttonSize = [tutorialOkButton frame].size; - const CGFloat kTopBottomTextPadding = 6; - const CGFloat kLeftRightTextPadding = 15; - buttonSize.width += 2 * kLeftRightTextPadding; - buttonSize.height += 2 * kTopBottomTextPadding; - [tutorialOkButton setFrameSize:buttonSize]; - CGFloat buttonXOffset = kFixedMenuWidth - - NSWidth([tutorialOkButton frame]) - - kHorizontalSpacing; - [tutorialOkButton setFrameOrigin:NSMakePoint(buttonXOffset, yOffset)]; - } - - if (linkMessage) { - CGFloat linkYOffset = yOffset; - if (buttonMessage) { - linkYOffset += (NSHeight([tutorialOkButton frame]) - - NSHeight([learnMoreLink frame])) / 2; - } - [learnMoreLink setFrameOrigin:NSMakePoint( - kHorizontalSpacing, linkYOffset)]; - } - } - - if (buttonMessage) { - [container addSubview:tutorialOkButton]; - yOffset = NSMaxY([tutorialOkButton frame]); - } - - if (linkMessage) { - [container addSubview:learnMoreLink]; - yOffset = std::max(NSMaxY([learnMoreLink frame]), yOffset); - } - - yOffset += kVerticalSpacing; - - // Adds body content. - NSTextField* contentLabel = BuildLabel( - contentMessage, - NSMakePoint(kHorizontalSpacing, yOffset), - skia::SkColorToSRGBNSColor(profiles::kAvatarTutorialContentTextColor)); - [contentLabel setFrameSize:NSMakeSize(availableWidth, 0)]; - [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:contentLabel]; - [container addSubview:contentLabel]; - yOffset = NSMaxY([contentLabel frame]) + kSmallVerticalSpacing; - - // Adds title. - NSTextField* titleLabel = - BuildLabel(titleMessage, - NSMakePoint(kHorizontalSpacing, yOffset), - [NSColor whiteColor] /* text_color */); - [titleLabel setFont:[NSFont labelFontOfSize:kTitleFontSize]]; - - if (hasCloseButton) { - base::scoped_nsobject<HoverImageButton> closeButton( - [[HoverImageButton alloc] initWithFrame:NSZeroRect]); - [closeButton setBordered:NO]; - - ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); - NSImage* closeImage = rb->GetNativeImageNamed(IDR_CLOSE_1).ToNSImage(); - CGFloat closeImageWidth = [closeImage size].width; - [closeButton setDefaultImage:closeImage]; - [closeButton setHoverImage: - rb->GetNativeImageNamed(IDR_CLOSE_1_H).ToNSImage()]; - [closeButton setPressedImage: - rb->GetNativeImageNamed(IDR_CLOSE_1_P).ToNSImage()]; - [closeButton setTarget:self]; - [closeButton setAction:@selector(dismissTutorial:)]; - [closeButton setFrameSize:[closeImage size]]; - [closeButton - setFrameOrigin:NSMakePoint(kFixedMenuWidth - kHorizontalSpacing - - closeImageWidth, - yOffset)]; - [container addSubview:closeButton]; - - [titleLabel setFrameSize:NSMakeSize( - availableWidth - closeImageWidth - kHorizontalSpacing, 0)]; - } else { - [titleLabel setFrameSize:NSMakeSize(availableWidth, 0)]; - } - - [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:titleLabel]; - [container addSubview:titleLabel]; - yOffset = NSMaxY([titleLabel frame]) + kVerticalSpacing; - - [container setFrameSize:NSMakeSize(kFixedMenuWidth, yOffset)]; - [container setFrameOrigin:NSZeroPoint]; - return container.autorelease(); -} - - (NSView*)buildSyncErrorViewIfNeeded { int contentStringId, buttonStringId; SEL buttonAction;
diff --git a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller_unittest.mm b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller_unittest.mm index 5ec616b..0f74dcee 100644 --- a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller_unittest.mm
@@ -89,18 +89,12 @@ } void StartProfileChooserController() { - StartProfileChooserControllerWithTutorialMode(profiles::TUTORIAL_MODE_NONE); - } - - void StartProfileChooserControllerWithTutorialMode( - profiles::TutorialMode mode) { NSRect frame = [test_window() frame]; NSPoint point = NSMakePoint(NSMidX(frame), NSMidY(frame)); controller_.reset([[ProfileChooserController alloc] initWithBrowser:browser() anchoredAt:point viewMode:profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER - tutorialMode:mode serviceType:signin::GAIA_SERVICE_TYPE_NONE accessPoint:signin_metrics::AccessPoint:: ACCESS_POINT_AVATAR_BUBBLE_SIGN_IN]); @@ -194,29 +188,6 @@ [controller() close]; } -TEST_F(ProfileChooserControllerTest, RightClickTutorialShownAfterWelcome) { - // The welcome upgrade tutorial takes precedence so show it then dismiss it. - // The right click tutorial should be shown right away. - StartProfileChooserControllerWithTutorialMode( - profiles::TUTORIAL_MODE_WELCOME_UPGRADE); - - [controller() dismissTutorial:nil]; -} - -TEST_F(ProfileChooserControllerTest, RightClickTutorialShownAfterReopen) { - // The welcome upgrade tutorial takes precedence so show it then close the - // menu. Reopening the menu should show the tutorial. - StartProfileChooserController(); - - [controller() close]; - StartProfileChooserController(); - - // The tutorial must be manually dismissed so it should still be shown after - // closing and reopening the menu, - [controller() close]; - StartProfileChooserController(); -} - TEST_F(ProfileChooserControllerTest, LocalProfileActiveCardLinksWithNewMenu) { StartProfileChooserController();
diff --git a/chrome/browser/ui/cocoa/profiles/user_manager_mac.mm b/chrome/browser/ui/cocoa/profiles/user_manager_mac.mm index b329ac1..0116bd6 100644 --- a/chrome/browser/ui/cocoa/profiles/user_manager_mac.mm +++ b/chrome/browser/ui/cocoa/profiles/user_manager_mac.mm
@@ -413,7 +413,6 @@ // static void UserManager::Show( const base::FilePath& profile_path_to_focus, - profiles::UserManagerTutorialMode tutorial_mode, profiles::UserManagerAction user_manager_action) { DCHECK(profile_path_to_focus != ProfileManager::GetGuestProfilePath()); @@ -437,7 +436,6 @@ // from the guest profile. profiles::CreateSystemProfileForUserManager( profile_path_to_focus, - tutorial_mode, user_manager_action, base::Bind(&UserManagerMac::OnSystemProfileCreated, base::Time::Now())); }
diff --git a/chrome/browser/ui/cocoa/profiles/user_manager_mac_unittest.mm b/chrome/browser/ui/cocoa/profiles/user_manager_mac_unittest.mm index f2dbbf4a..4cc3abee 100644 --- a/chrome/browser/ui/cocoa/profiles/user_manager_mac_unittest.mm +++ b/chrome/browser/ui/cocoa/profiles/user_manager_mac_unittest.mm
@@ -57,7 +57,6 @@ EXPECT_FALSE(UserManager::IsShowing()); UserManager::Show(base::FilePath(), - profiles::USER_MANAGER_NO_TUTORIAL, profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); EXPECT_TRUE(UserManager::IsShowing());
diff --git a/chrome/browser/ui/extensions/extension_enable_flow.cc b/chrome/browser/ui/extensions/extension_enable_flow.cc index 9af3285..19b9dff 100644 --- a/chrome/browser/ui/extensions/extension_enable_flow.cc +++ b/chrome/browser/ui/extensions/extension_enable_flow.cc
@@ -99,7 +99,6 @@ if (profiles::IsProfileLocked(profile_->GetPath())) { UserManager::Show(base::FilePath(), - profiles::USER_MANAGER_NO_TUTORIAL, profiles::USER_MANAGER_SELECT_PROFILE_APP_LAUNCHER); return; }
diff --git a/chrome/browser/ui/extensions/extension_message_bubble_bridge.cc b/chrome/browser/ui/extensions/extension_message_bubble_bridge.cc index 32e335a..a60d365 100644 --- a/chrome/browser/ui/extensions/extension_message_bubble_bridge.cc +++ b/chrome/browser/ui/extensions/extension_message_bubble_bridge.cc
@@ -52,10 +52,13 @@ base::string16 ExtensionMessageBubbleBridge::GetActionButtonText() { const extensions::ExtensionIdList& list = controller_->GetExtensionIdList(); DCHECK(!list.empty()); + // Normally, the extension is enabled, but this might not be the case (such as + // for the SuspiciousExtensionBubbleDelegate, which warns the user about + // disabled extensions). const extensions::Extension* extension = extensions::ExtensionRegistry::Get(controller_->profile()) - ->enabled_extensions() - .GetByID(list[0]); + ->GetExtensionById(list[0], + extensions::ExtensionRegistry::EVERYTHING); DCHECK(extension); // An empty string is returned so that we don't display the button prompting
diff --git a/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc b/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc index 99d3ae1..f2557f4 100644 --- a/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc +++ b/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc
@@ -122,8 +122,14 @@ extensions::extension_action_test_util::CreateActionExtension( "no_action_extension", extensions::extension_action_test_util::NO_ACTION, - extensions::Manifest::UNPACKED); + extensions::Manifest::INTERNAL); extension_service()->AddExtension(no_action_extension.get()); + // The 'suspicious extension' bubble warns the user about extensions that are + // disabled for not being from the webstore. This is one of the few bubbles + // that lets us test anchoring to the app menu, since we usually anchor to the + // extension action now that every extension is given a permanent UI presence. + extension_service()->DisableExtension( + no_action_extension->id(), extensions::Extension::DISABLE_NOT_VERIFIED); Browser* second_browser = new Browser(Browser::CreateParams(profile(), true)); ASSERT_TRUE(second_browser); second_browser->window()->Show(); @@ -138,7 +144,7 @@ extensions::extension_action_test_util::CreateActionExtension( "no_action_extension", extensions::extension_action_test_util::NO_ACTION, - extensions::Manifest::UNPACKED); + extensions::Manifest::INTERNAL); extension_service()->AddExtension(no_action_extension.get()); scoped_refptr<const extensions::Extension> action_extension = @@ -148,6 +154,13 @@ extensions::Manifest::INTERNAL); extension_service()->AddExtension(action_extension.get()); + // The 'suspicious extension' bubble warns the user about extensions that are + // disabled for not being from the webstore. This is one of the few bubbles + // that lets us test anchoring to the app menu, since we usually anchor to the + // extension action now that every extension is given a permanent UI presence. + extension_service()->DisableExtension( + no_action_extension->id(), extensions::Extension::DISABLE_NOT_VERIFIED); + Browser* second_browser = new Browser(Browser::CreateParams(profile(), true)); ASSERT_TRUE(second_browser); second_browser->window()->Show();
diff --git a/chrome/browser/ui/profile_chooser_constants.h b/chrome/browser/ui/profile_chooser_constants.h index d18f4e3..52adfbd 100644 --- a/chrome/browser/ui/profile_chooser_constants.h +++ b/chrome/browser/ui/profile_chooser_constants.h
@@ -29,18 +29,6 @@ BUBBLE_VIEW_MODE_SWITCH_USER, }; -// Tutorial modes that can be displayed in the profile chooser bubble. -enum TutorialMode { - // No tutorial card shown. - TUTORIAL_MODE_NONE, - // A tutorial card shown to confirm Chrome signin. - TUTORIAL_MODE_CONFIRM_SIGNIN, - // A tutorial card shown to introduce an upgrade user to the new avatar menu. - TUTORIAL_MODE_WELCOME_UPGRADE, - // A tutorial card shown to display the signin errors. - TUTORIAL_MODE_SHOW_ERROR, -}; - }; // namespace profiles #endif // CHROME_BROWSER_UI_PROFILE_CHOOSER_CONSTANTS_H_
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc index 2777068c..994ee56 100644 --- a/chrome/browser/ui/startup/startup_browser_creator.cc +++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -297,8 +297,7 @@ command_line.HasSwitch(switches::kShowAppList) ? profiles::USER_MANAGER_SELECT_PROFILE_APP_LAUNCHER : profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION; - UserManager::Show( - base::FilePath(), profiles::USER_MANAGER_NO_TUTORIAL, action); + UserManager::Show(base::FilePath(), action); return true; }
diff --git a/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc b/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc index 992e89f..e474aea 100644 --- a/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc +++ b/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc
@@ -71,10 +71,6 @@ base::CommandLine* command_line) { ExtensionBrowserTest::SetUpCommandLine(command_line); ToolbarActionsBar::disable_animations_for_testing_ = true; - // These tests are deliberately testing behavior without the redesign. - // Forcefully disable it. - override_redesign_.reset(new extensions::FeatureSwitch::ScopedOverride( - extensions::FeatureSwitch::extension_action_redesign(), true)); } void BrowserActionsBarBrowserTest::SetUpOnMainThread() { @@ -112,40 +108,24 @@ } } -// BrowserActionsBarLegacyBrowserTest: - -BrowserActionsBarLegacyBrowserTest::BrowserActionsBarLegacyBrowserTest() { -} - -BrowserActionsBarLegacyBrowserTest::~BrowserActionsBarLegacyBrowserTest() { -} - -void BrowserActionsBarLegacyBrowserTest::SetUpCommandLine( - base::CommandLine* command_line) { - BrowserActionsBarBrowserTest::SetUpCommandLine(command_line); - // Override to force the redesign. Completely clear the previous override - // first, since doing so resets the value of the switch. - override_redesign_.reset(); - override_redesign_.reset(new extensions::FeatureSwitch::ScopedOverride( - extensions::FeatureSwitch::extension_action_redesign(), false)); -} - // Test the basic functionality. -IN_PROC_BROWSER_TEST_F(BrowserActionsBarLegacyBrowserTest, Basic) { +IN_PROC_BROWSER_TEST_F(BrowserActionsBarBrowserTest, Basic) { // Load an extension with no browser action. extension_service()->AddExtension(CreateExtension("alpha", false).get()); - // This extension should not be in the model (has no browser action). - EXPECT_EQ(0, browser_actions_bar()->NumberOfBrowserActions()); - - // Load an extension with a browser action. - extension_service()->AddExtension(CreateExtension("beta", true).get()); + // This extension should be present in the model (it will receive a + // synthesized action). EXPECT_EQ(1, browser_actions_bar()->NumberOfBrowserActions()); EXPECT_TRUE(browser_actions_bar()->HasIcon(0)); - // Unload the extension. - std::string id = browser_actions_bar()->GetExtensionId(0); + // Load an extension with a browser action; it will also be in the toolbar. + extension_service()->AddExtension(CreateExtension("beta", true).get()); + EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions()); + EXPECT_TRUE(browser_actions_bar()->HasIcon(1)); + + // Unload the extension; the icon should be removed. + std::string id = browser_actions_bar()->GetExtensionId(1); UnloadExtension(id); - EXPECT_EQ(0, browser_actions_bar()->NumberOfBrowserActions()); + EXPECT_EQ(1, browser_actions_bar()->NumberOfBrowserActions()); } // Test moving various browser actions. This is not to check the logic of the @@ -180,21 +160,6 @@ EXPECT_EQ(extension_a()->id(), browser_actions_bar()->GetExtensionId(2)); } -// Test that explicitly hiding an extension action results in it disappearing -// from the browser actions bar. -IN_PROC_BROWSER_TEST_F(BrowserActionsBarLegacyBrowserTest, ForceHide) { - LoadExtensions(); - - EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions()); - EXPECT_EQ(extension_a()->id(), browser_actions_bar()->GetExtensionId(0)); - // Force hide one of the extensions' browser action. - extensions::ExtensionActionAPI::Get(browser()->profile())-> - SetBrowserActionVisibility(extension_a()->id(), false); - // The browser action for Extension A should be removed. - EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions()); - EXPECT_EQ(extension_b()->id(), browser_actions_bar()->GetExtensionId(0)); -} - IN_PROC_BROWSER_TEST_F(BrowserActionsBarBrowserTest, Visibility) { LoadExtensions();
diff --git a/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.h b/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.h index dcb7476..08fe6fb 100644 --- a/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.h +++ b/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.h
@@ -10,7 +10,6 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "chrome/browser/extensions/extension_browsertest.h" -#include "extensions/common/feature_switch.h" namespace extensions { class Extension; @@ -49,12 +48,6 @@ return extension_c_.get(); } - protected: - // Enable or disable the feature redesign switch. - std::unique_ptr<extensions::FeatureSwitch::ScopedOverride> override_redesign_; - std::unique_ptr<extensions::FeatureSwitch::ScopedOverride> - override_media_router_; - private: std::unique_ptr<BrowserActionTestUtil> browser_actions_bar_; @@ -69,17 +62,4 @@ DISALLOW_COPY_AND_ASSIGN(BrowserActionsBarBrowserTest); }; -// A test with the extension-action-redesign switch disabled. -class BrowserActionsBarLegacyBrowserTest - : public BrowserActionsBarBrowserTest { - protected: - BrowserActionsBarLegacyBrowserTest(); - ~BrowserActionsBarLegacyBrowserTest() override; - - void SetUpCommandLine(base::CommandLine* command_line) override; - - private: - DISALLOW_COPY_AND_ASSIGN(BrowserActionsBarLegacyBrowserTest); -}; - #endif // CHROME_BROWSER_UI_TOOLBAR_BROWSER_ACTIONS_BAR_BROWSERTEST_H_
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar.cc b/chrome/browser/ui/toolbar/toolbar_actions_bar.cc index d013ae08..1f76ec09 100644 --- a/chrome/browser/ui/toolbar/toolbar_actions_bar.cc +++ b/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
@@ -35,7 +35,6 @@ #include "extensions/browser/extension_util.h" #include "extensions/browser/runtime_data.h" #include "extensions/common/extension.h" -#include "extensions/common/feature_switch.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/image/image_skia.h" @@ -90,10 +89,7 @@ ToolbarActionsBar::PlatformSettings::PlatformSettings() : item_spacing(GetLayoutConstant(TOOLBAR_STANDARD_SPACING)), - icons_per_overflow_menu_row(1), - chevron_enabled(!extensions::FeatureSwitch::extension_action_redesign()-> - IsEnabled()) { -} + icons_per_overflow_menu_row(1) {} ToolbarActionsBar::ToolbarActionsBar(ToolbarActionsBarDelegate* delegate, Browser* browser, @@ -267,8 +263,7 @@ // popped out action (because the action will pop back into overflow when the // menu opens). return GetEndIndexInBounds() != toolbar_actions_.size() || - (is_drag_in_progress_ && !platform_settings_.chevron_enabled) || - (popped_out_action_ && !is_popped_out_sticky_); + is_drag_in_progress_ || (popped_out_action_ && !is_popped_out_sticky_); } gfx::Rect ToolbarActionsBar::GetFrameForIndex( @@ -514,7 +509,7 @@ delegate_->Redraw(true); } - ResizeDelegate(gfx::Tween::LINEAR, false); + ResizeDelegate(gfx::Tween::LINEAR); if (!delegate_->IsAnimating()) { // Don't call the closure re-entrantly. base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, closure); @@ -532,7 +527,7 @@ popped_out_closure_.Reset(); if (!IsActionVisibleOnMainBar(controller)) delegate_->Redraw(true); - ResizeDelegate(gfx::Tween::LINEAR, false); + ResizeDelegate(gfx::Tween::LINEAR); } void ToolbarActionsBar::SetPopupOwner( @@ -633,15 +628,12 @@ model_->CreateActionForItem(browser_, this, item)); delegate_->AddViewForAction(toolbar_actions_[index].get(), index); - // We may need to resize (e.g. to show the new icon, or the chevron). We don't - // need to check if an extension is upgrading here, because ResizeDelegate() - // checks to see if the container is already the proper size, and because - // if the action is newly incognito enabled, even though it's a reload, it's - // a new extension to this toolbar. - // We suppress the chevron during animation because, if we're expanding to - // show a new icon, we don't want to have the chevron visible only for the - // duration of the animation. - ResizeDelegate(gfx::Tween::LINEAR, true); + // We may need to resize (e.g. to show the new icon). We don't need to check + // if an extension is upgrading here, because ResizeDelegate() checks to see + // if the container is already the proper size, and because if the action is + // newly incognito enabled, even though it's a reload, it's a new extension to + // this toolbar. + ResizeDelegate(gfx::Tween::LINEAR); } void ToolbarActionsBar::OnToolbarActionRemoved(const std::string& action_id) { @@ -681,7 +673,7 @@ } else { // Either we went from overflow to no-overflow, or we shrunk the no- // overflow container by 1. Either way the size changed, so animate. - ResizeDelegate(gfx::Tween::EASE_OUT, false); + ResizeDelegate(gfx::Tween::EASE_OUT); } } } @@ -704,11 +696,10 @@ } void ToolbarActionsBar::OnToolbarVisibleCountChanged() { - ResizeDelegate(gfx::Tween::EASE_OUT, false); + ResizeDelegate(gfx::Tween::EASE_OUT); } -void ToolbarActionsBar::ResizeDelegate(gfx::Tween::Type tween_type, - bool suppress_chevron) { +void ToolbarActionsBar::ResizeDelegate(gfx::Tween::Type tween_type) { int desired_width = GetFullSize().width(); if (desired_width != delegate_->GetWidth(ToolbarActionsBarDelegate::GET_WIDTH_CURRENT)) { @@ -782,7 +773,7 @@ tracked_objects::ScopedTracker tracking_profile( FROM_HERE_WITH_EXPLICIT_FUNCTION( "ToolbarActionsBar::OnToolbarModelInitialized")); - ResizeDelegate(gfx::Tween::EASE_OUT, false); + ResizeDelegate(gfx::Tween::EASE_OUT); } void ToolbarActionsBar::TabInsertedAt(TabStripModel* tab_strip_model, @@ -807,7 +798,7 @@ // Our visible browser actions may have changed - re-Layout() and check the // size (if we aren't suppressing the layout). if (!suppress_layout_) { - ResizeDelegate(gfx::Tween::EASE_OUT, false); + ResizeDelegate(gfx::Tween::EASE_OUT); delegate_->Redraw(true); } }
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar.h b/chrome/browser/ui/toolbar/toolbar_actions_bar.h index 3675218..6a7f37f 100644 --- a/chrome/browser/ui/toolbar/toolbar_actions_bar.h +++ b/chrome/browser/ui/toolbar/toolbar_actions_bar.h
@@ -60,9 +60,6 @@ int item_spacing; // The number of icons per row in the overflow menu. int icons_per_overflow_menu_row; - // Whether or not the overflow menu is displayed as a chevron (this is being - // phased out). - bool chevron_enabled; }; // The type of drag that occurred in a drag-and-drop operation. @@ -274,8 +271,8 @@ bool foreground) override; // Resizes the delegate (if necessary) to the preferred size using the given - // |tween_type| and optionally suppressing the chevron. - void ResizeDelegate(gfx::Tween::Type tween_type, bool suppress_chevron); + // |tween_type|. + void ResizeDelegate(gfx::Tween::Type tween_type); // Returns the action for the given |id|, if one exists. ToolbarActionViewController* GetActionForId(const std::string& action_id); @@ -304,7 +301,7 @@ // is the main bar. ToolbarActionsBar* main_bar_; - // Platform-specific settings for dimensions and the overflow chevron. + // Platform-specific settings for dimensions. PlatformSettings platform_settings_; // The toolbar actions.
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc b/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc index 84b8a6f..de8ac79 100644 --- a/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc +++ b/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc
@@ -25,7 +25,6 @@ #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_system.h" #include "extensions/common/extension.h" -#include "extensions/common/feature_switch.h" #include "ui/base/test/material_design_controller_test_api.h" namespace { @@ -115,10 +114,8 @@ ToolbarActionsBar::disable_animations_for_testing_ = true; browser_action_test_util_.reset(new BrowserActionTestUtil(browser(), false)); - if (extensions::FeatureSwitch::extension_action_redesign()->IsEnabled()) { - overflow_browser_action_test_util_ = - browser_action_test_util_->CreateOverflowBar(); - } + overflow_browser_action_test_util_ = + browser_action_test_util_->CreateOverflowBar(); } void ToolbarActionsBarUnitTest::TearDown() { @@ -169,15 +166,9 @@ total_size, visible_count); std::string overflow_bar_error; - if (extensions::FeatureSwitch::extension_action_redesign()->IsEnabled()) { - overflow_bar_error = - VerifyToolbarOrderForBar(overflow_bar(), - overflow_browser_action_test_util(), - expected_names, - total_size, - total_size - visible_count); - - } + overflow_bar_error = VerifyToolbarOrderForBar( + overflow_bar(), overflow_browser_action_test_util(), expected_names, + total_size, total_size - visible_count); return main_bar_error.empty() && overflow_bar_error.empty() ? testing::AssertionSuccess() :
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model.cc b/chrome/browser/ui/toolbar/toolbar_actions_model.cc index 4350ad2..abbb2cf0 100644 --- a/chrome/browser/ui/toolbar/toolbar_actions_model.cc +++ b/chrome/browser/ui/toolbar/toolbar_actions_model.cc
@@ -36,7 +36,6 @@ #include "extensions/browser/extension_util.h" #include "extensions/browser/pref_names.h" #include "extensions/common/extension_set.h" -#include "extensions/common/feature_switch.h" #include "extensions/common/manifest_constants.h" #include "extensions/common/one_shot_event.h" @@ -53,8 +52,6 @@ component_actions_factory_( base::MakeUnique<ComponentToolbarActionsFactory>(profile_)), actions_initialized_(false), - use_redesign_( - extensions::FeatureSwitch::extension_action_redesign()->IsEnabled()), highlight_type_(HIGHLIGHT_NONE), has_active_bubble_(false), extension_action_observer_(this), @@ -191,7 +188,6 @@ break; } case COMPONENT_ACTION: { - DCHECK(use_redesign_); result = component_actions_factory_->GetComponentToolbarActionForId( item.id, browser, bar); break; @@ -203,18 +199,6 @@ return result; } -void ToolbarActionsModel::OnExtensionActionVisibilityChanged( - const std::string& extension_id, - bool is_now_visible) { - if (use_redesign_) - return; - const extensions::Extension* extension = GetExtensionById(extension_id); - if (is_now_visible) - AddExtension(extension); - else - RemoveExtension(extension); -} - void ToolbarActionsModel::OnExtensionLoaded( content::BrowserContext* browser_context, const extensions::Extension* extension) { @@ -271,11 +255,9 @@ for (Observer& observer : observers_) observer.OnToolbarModelInitialized(); - if (use_redesign_) { - component_actions_factory_->UnloadMigratedExtensions( - extensions::ExtensionSystem::Get(profile_)->extension_service(), - extension_registry_); - } + component_actions_factory_->UnloadMigratedExtensions( + extensions::ExtensionSystem::Get(profile_)->extension_service(), + extension_registry_); } size_t ToolbarActionsModel::FindNewPositionFromLastKnownGood( @@ -308,14 +290,9 @@ !extensions::util::IsIncognitoEnabled(extension->id(), profile_)) return false; - if (use_redesign_) { - // In this case, we don't care about the browser action visibility, because - // we want to show each extension regardless. - return extension_action_manager_->GetExtensionAction(*extension) != nullptr; - } - - return extension_action_manager_->GetBrowserAction(*extension) && - extension_action_api_->GetBrowserActionVisibility(extension->id()); + // In this case, we don't care about the browser action visibility, because + // we want to show each extension regardless. + return extension_action_manager_->GetExtensionAction(*extension) != nullptr; } void ToolbarActionsModel::AddExtension(const extensions::Extension* extension) { @@ -608,14 +585,10 @@ ? base::HistogramBase::kSampleType_MAX : visible_icon_count_ - component_actions_count); - if (use_redesign_) { - // The only time this will useful and possibly vary from - // BrowserActionsVisible is when the redesign has been enabled. - UMA_HISTOGRAM_COUNTS_100("Toolbar.ActionsModel.ToolbarActionsVisible", - visible_icon_count_ == -1 - ? base::HistogramBase::kSampleType_MAX - : visible_icon_count_); - } + UMA_HISTOGRAM_COUNTS_100("Toolbar.ActionsModel.ToolbarActionsVisible", + visible_icon_count_ == -1 + ? base::HistogramBase::kSampleType_MAX + : visible_icon_count_); } } @@ -625,12 +598,10 @@ bool ToolbarActionsModel::HasComponentAction( const std::string& action_id) const { - DCHECK(use_redesign_); return HasItem(ToolbarItem(action_id, COMPONENT_ACTION)); } void ToolbarActionsModel::AddComponentAction(const std::string& action_id) { - DCHECK(use_redesign_); if (!actions_initialized_) { component_actions_factory_->OnAddComponentActionBeforeInit(action_id); return; @@ -642,7 +613,6 @@ } void ToolbarActionsModel::RemoveComponentAction(const std::string& action_id) { - DCHECK(use_redesign_); if (!actions_initialized_) { component_actions_factory_->OnRemoveComponentActionBeforeInit(action_id); return; @@ -715,35 +685,26 @@ void ToolbarActionsModel::SetActionVisibility(const std::string& action_id, bool is_now_visible) { // Hiding works differently with the new and old toolbars. - if (use_redesign_) { - DCHECK(HasItem(ToolbarItem(action_id, EXTENSION_ACTION))); + DCHECK(HasItem(ToolbarItem(action_id, EXTENSION_ACTION))); - int new_size = 0; - int new_index = 0; - if (is_now_visible) { - // If this action used to be hidden, we can't possibly be showing all. - DCHECK_LT(visible_icon_count(), toolbar_items_.size()); - // Grow the bar by one and move the action to the end of the visibles. - new_size = visible_icon_count() + 1; - new_index = new_size - 1; - } else { - // If we're hiding one, we must be showing at least one. - DCHECK_GE(visible_icon_count(), 0u); - // Shrink the bar by one and move the action to the beginning of the - // overflow menu. - new_size = visible_icon_count() - 1; - new_index = new_size; - } - SetVisibleIconCount(new_size); - MoveActionIcon(action_id, new_index); - } else { // Legacy toolbar; hiding removes it from the toolbar. - if (!profile_->IsOffTheRecord()) { - extension_action_api_->SetBrowserActionVisibility(action_id, - is_now_visible); - } else { - OnExtensionActionVisibilityChanged(action_id, is_now_visible); - } + int new_size = 0; + int new_index = 0; + if (is_now_visible) { + // If this action used to be hidden, we can't possibly be showing all. + DCHECK_LT(visible_icon_count(), toolbar_items_.size()); + // Grow the bar by one and move the action to the end of the visibles. + new_size = visible_icon_count() + 1; + new_index = new_size - 1; + } else { + // If we're hiding one, we must be showing at least one. + DCHECK_GE(visible_icon_count(), 0u); + // Shrink the bar by one and move the action to the beginning of the + // overflow menu. + new_size = visible_icon_count() - 1; + new_index = new_size; } + SetVisibleIconCount(new_size); + MoveActionIcon(action_id, new_index); } void ToolbarActionsModel::OnActionToolbarPrefChange() {
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model.h b/chrome/browser/ui/toolbar/toolbar_actions_model.h index 8f01c23..662844d 100644 --- a/chrome/browser/ui/toolbar/toolbar_actions_model.h +++ b/chrome/browser/ui/toolbar/toolbar_actions_model.h
@@ -225,8 +225,6 @@ ExtensionAction* extension_action, content::WebContents* web_contents, content::BrowserContext* browser_context) override; - void OnExtensionActionVisibilityChanged(const std::string& extension_id, - bool is_now_visible) override; // To be called after the extension service is ready; gets loaded extensions // from the ExtensionRegistry, their saved order from the pref service, and @@ -299,9 +297,6 @@ // True if we've handled the initial EXTENSIONS_READY notification. bool actions_initialized_; - // If true, we include all actions in the toolbar model. - bool use_redesign_; - // Ordered list of browser actions. std::vector<ToolbarItem> toolbar_items_;
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc b/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc index 158a2eb..6fd4609 100644 --- a/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc +++ b/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc
@@ -43,7 +43,6 @@ #include "extensions/browser/uninstall_reason.h" #include "extensions/common/extension.h" #include "extensions/common/extension_builder.h" -#include "extensions/common/feature_switch.h" #include "extensions/common/manifest.h" #include "extensions/common/value_builder.h" @@ -836,24 +835,10 @@ EXPECT_EQ(num_toolbar_items(), toolbar_model()->visible_icon_count()); } -// Test that, in the absence of the extension-action-redesign switch, the -// model only contains extensions with browser actions and component actions. -TEST_F(ToolbarActionsModelUnitTest, TestToolbarExtensionTypesDisabledSwitch) { - extensions::FeatureSwitch::ScopedOverride enable_redesign( - extensions::FeatureSwitch::extension_action_redesign(), false); - Init(); - ASSERT_TRUE(AddActionExtensions()); - - EXPECT_EQ(1u, num_toolbar_items()); - EXPECT_EQ(browser_action()->id(), GetActionIdAtIndex(0u)); -} - // Test that, with the extension-action-redesign switch, the model contains // all types of extensions, except those which should not be displayed on the // toolbar (like component extensions). TEST_F(ToolbarActionsModelUnitTest, TestToolbarExtensionTypesEnabledSwitch) { - extensions::FeatureSwitch::ScopedOverride enable_redesign( - extensions::FeatureSwitch::extension_action_redesign(), true); Init(); ASSERT_TRUE(AddActionExtensions()); @@ -904,48 +889,6 @@ EXPECT_TRUE(ModelHasActionForId(internal_extension_no_action->id())); } -// Test that hiding actions on the toolbar results in their removal from the -// model when the redesign switch is not enabled. -TEST_F(ToolbarActionsModelUnitTest, ActionsToolbarActionsVisibilityNoSwitch) { - extensions::FeatureSwitch::ScopedOverride enable_redesign( - extensions::FeatureSwitch::extension_action_redesign(), false); - Init(); - - extensions::ExtensionActionAPI* action_api = - extensions::ExtensionActionAPI::Get(profile()); - - ASSERT_TRUE(AddBrowserActionExtensions()); - // Sanity check: Order should start as A , B, C. - EXPECT_EQ(3u, num_toolbar_items()); - EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u)); - EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u)); - EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2u)); - - // By default, all actions should be visible. - EXPECT_TRUE(action_api->GetBrowserActionVisibility(browser_action_a()->id())); - EXPECT_TRUE(action_api->GetBrowserActionVisibility(browser_action_b()->id())); - EXPECT_TRUE(action_api->GetBrowserActionVisibility(browser_action_c()->id())); - - // Hiding an action should result in its removal from the toolbar. - action_api->SetBrowserActionVisibility(browser_action_b()->id(), false); - EXPECT_FALSE( - action_api->GetBrowserActionVisibility(browser_action_b()->id())); - // Thus, there should now only be two items on the toolbar - A and C. - EXPECT_EQ(2u, num_toolbar_items()); - EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u)); - EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(1u)); - - // Resetting the visibility to 'true' should result in the extension being - // added back at its original position. - action_api->SetBrowserActionVisibility(browser_action_b()->id(), true); - EXPECT_TRUE(action_api->GetBrowserActionVisibility(browser_action_b()->id())); - // So the toolbar order should be A, B, C. - EXPECT_EQ(3u, num_toolbar_items()); - EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u)); - EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u)); - EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2u)); -} - TEST_F(ToolbarActionsModelUnitTest, ActionsToolbarIncognitoModeTest) { Init(); ASSERT_TRUE(AddBrowserActionExtensions()); @@ -1120,8 +1063,6 @@ // overflow menu when the redesign switch is enabled. TEST_F(ToolbarActionsModelUnitTest, ActionsToolbarActionsVisibilityWithSwitchAndComponentActions) { - extensions::FeatureSwitch::ScopedOverride enable_redesign( - extensions::FeatureSwitch::extension_action_redesign(), true); Init(); // We choose to use all types of extensions here, since the misnamed @@ -1249,8 +1190,6 @@ // toolbar with component actions. TEST_F(ToolbarActionsModelUnitTest, ActionsToolbarReorderAndReinsertWithSwitchAndComponentActions) { - extensions::FeatureSwitch::ScopedOverride enable_redesign( - extensions::FeatureSwitch::extension_action_redesign(), true); InitWithMockActionsFactory(); // One component action was added when the model was initialized.
diff --git a/chrome/browser/ui/user_manager.h b/chrome/browser/ui/user_manager.h index 508ac9ac..161150a 100644 --- a/chrome/browser/ui/user_manager.h +++ b/chrome/browser/ui/user_manager.h
@@ -25,12 +25,10 @@ // Shows the User Manager or re-activates an existing one, focusing the // profile given by |profile_path_to_focus|; passing an empty base::FilePath - // focuses no user pod. Based on the value of |tutorial_mode|, a tutorial - // could be shown, in which case |profile_path_to_focus| is ignored. Depending - // on the value of |user_manager_action|, executes an action once the user - // manager displays or after a profile is opened. + // focuses no user pod. Depending on the value of |user_manager_action|, + // executes an action once the user manager displays or after a profile is + // opened. static void Show(const base::FilePath& profile_path_to_focus, - profiles::UserManagerTutorialMode tutorial_mode, profiles::UserManagerAction user_manager_action); // Hides the User Manager.
diff --git a/chrome/browser/ui/views/extensions/extension_message_bubble_view_browsertest.cc b/chrome/browser/ui/views/extensions/extension_message_bubble_view_browsertest.cc index 94f853ec..760f3659 100644 --- a/chrome/browser/ui/views/extensions/extension_message_bubble_view_browsertest.cc +++ b/chrome/browser/ui/views/extensions/extension_message_bubble_view_browsertest.cc
@@ -70,17 +70,6 @@ DISALLOW_COPY_AND_ASSIGN(ExtensionMessageBubbleViewBrowserTest); }; -class ExtensionMessageBubbleViewBrowserTestLegacy - : public ExtensionMessageBubbleViewBrowserTest { - protected: - void SetUpCommandLine(base::CommandLine* command_line) override { - ExtensionMessageBubbleViewBrowserTest::SetUpCommandLine(command_line); - override_redesign_.reset(); - override_redesign_.reset(new extensions::FeatureSwitch::ScopedOverride( - extensions::FeatureSwitch::extension_action_redesign(), false)); - } -}; - void ExtensionMessageBubbleViewBrowserTest::SetUpCommandLine( base::CommandLine* command_line) { ExtensionMessageBubbleBrowserTest::SetUpCommandLine(command_line); @@ -163,12 +152,12 @@ TestBubbleAnchoredToExtensionAction(); } -IN_PROC_BROWSER_TEST_F(ExtensionMessageBubbleViewBrowserTestLegacy, +IN_PROC_BROWSER_TEST_F(ExtensionMessageBubbleViewBrowserTest, ExtensionBubbleAnchoredToAppMenu) { TestBubbleAnchoredToAppMenu(); } -IN_PROC_BROWSER_TEST_F(ExtensionMessageBubbleViewBrowserTestLegacy, +IN_PROC_BROWSER_TEST_F(ExtensionMessageBubbleViewBrowserTest, ExtensionBubbleAnchoredToAppMenuWithOtherAction) { TestBubbleAnchoredToAppMenuWithOtherAction(); }
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index 6120c4b..1a2486d 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -2526,15 +2526,13 @@ return; profiles::BubbleViewMode bubble_view_mode; - profiles::TutorialMode tutorial_mode; - profiles::BubbleViewModeFromAvatarBubbleMode(mode, &bubble_view_mode, - &tutorial_mode); + profiles::BubbleViewModeFromAvatarBubbleMode(mode, &bubble_view_mode); if (SigninViewController::ShouldShowModalSigninForMode(bubble_view_mode)) { browser_->signin_view_controller()->ShowModalSignin( bubble_view_mode, browser_.get(), access_point); } else { - ProfileChooserView::ShowBubble(bubble_view_mode, tutorial_mode, - manage_accounts_params, access_point, + ProfileChooserView::ShowBubble(bubble_view_mode, manage_accounts_params, + access_point, frame_->GetNewAvatarMenuButton(), browser(), focus_first_profile_button); ProfileMetrics::LogProfileOpenMethod(ProfileMetrics::ICON_AVATAR_BUBBLE);
diff --git a/chrome/browser/ui/views/frame/windows_10_caption_button.cc b/chrome/browser/ui/views/frame/windows_10_caption_button.cc index 1ee72aa9..b88a330 100644 --- a/chrome/browser/ui/views/frame/windows_10_caption_button.cc +++ b/chrome/browser/ui/views/frame/windows_10_caption_button.cc
@@ -58,12 +58,9 @@ return color_utils::IsDark(blend_color) ? SK_ColorWHITE : SK_ColorBLACK; } -void Windows10CaptionButton::OnPaint(gfx::Canvas* canvas) { - PaintBackground(canvas); - PaintSymbol(canvas); -} - -void Windows10CaptionButton::PaintBackground(gfx::Canvas* canvas) { +void Windows10CaptionButton::OnPaintBackground(gfx::Canvas* canvas) { + // Paint the background of the button (the semi-transparent rectangle that + // appears when you hover or press the button). const ui::ThemeProvider* theme_provider = GetThemeProvider(); const SkColor bg_color = theme_provider->GetColor(ThemeProperties::COLOR_BUTTON_BACKGROUND); @@ -109,6 +106,10 @@ canvas->FillRect(GetContentsBounds(), SkColorSetA(base_color, alpha)); } +void Windows10CaptionButton::PaintButtonContents(gfx::Canvas* canvas) { + PaintSymbol(canvas); +} + namespace { // Canvas::DrawRect's stroke can bleed out of |rect|'s bounds, so this draws a
diff --git a/chrome/browser/ui/views/frame/windows_10_caption_button.h b/chrome/browser/ui/views/frame/windows_10_caption_button.h index 44ea3656..60bdeaa 100644 --- a/chrome/browser/ui/views/frame/windows_10_caption_button.h +++ b/chrome/browser/ui/views/frame/windows_10_caption_button.h
@@ -17,17 +17,14 @@ // views::CustomButton: gfx::Size CalculatePreferredSize() const override; - void OnPaint(gfx::Canvas* canvas) override; + void OnPaintBackground(gfx::Canvas* canvas) override; + void PaintButtonContents(gfx::Canvas* canvas) override; private: // The base color to use for the button symbols and background blending. Uses // the more readable of black and white. SkColor GetBaseColor() const; - // Paints the background of the button (the semi-transparent rectangle that - // appears when you hover or press the button). - void PaintBackground(gfx::Canvas* canvas); - // Paints the minimize/maximize/restore/close icon for the button. void PaintSymbol(gfx::Canvas* canvas);
diff --git a/chrome/browser/ui/views/passwords/credentials_item_view.cc b/chrome/browser/ui/views/passwords/credentials_item_view.cc index 5976ca7..905d4a2a47 100644 --- a/chrome/browser/ui/views/passwords/credentials_item_view.cc +++ b/chrome/browser/ui/views/passwords/credentials_item_view.cc
@@ -195,9 +195,7 @@ } } -void CredentialsItemView::OnPaint(gfx::Canvas* canvas) { +void CredentialsItemView::OnPaintBackground(gfx::Canvas* canvas) { if (state() == STATE_PRESSED || state() == STATE_HOVERED) canvas->DrawColor(hover_color_); - - CustomButton::OnPaint(canvas); }
diff --git a/chrome/browser/ui/views/passwords/credentials_item_view.h b/chrome/browser/ui/views/passwords/credentials_item_view.h index adffb5b..054c222b 100644 --- a/chrome/browser/ui/views/passwords/credentials_item_view.h +++ b/chrome/browser/ui/views/passwords/credentials_item_view.h
@@ -55,7 +55,7 @@ gfx::Size CalculatePreferredSize() const override; int GetHeightForWidth(int w) const override; void Layout() override; - void OnPaint(gfx::Canvas* canvas) override; + void OnPaintBackground(gfx::Canvas* canvas) override; const autofill::PasswordForm* form_;
diff --git a/chrome/browser/ui/views/profiles/profile_chooser_view.cc b/chrome/browser/ui/views/profiles/profile_chooser_view.cc index 186376d9..e7535c42 100644 --- a/chrome/browser/ui/views/profiles/profile_chooser_view.cc +++ b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
@@ -508,22 +508,16 @@ // static void ProfileChooserView::ShowBubble( profiles::BubbleViewMode view_mode, - profiles::TutorialMode tutorial_mode, const signin::ManageAccountsParams& manage_accounts_params, signin_metrics::AccessPoint access_point, views::View* anchor_view, Browser* browser, bool is_source_keyboard) { - if (IsShowing()) { - if (tutorial_mode != profiles::TUTORIAL_MODE_NONE) { - profile_bubble_->tutorial_mode_ = tutorial_mode; - profile_bubble_->ShowViewFromMode(view_mode); - } + if (IsShowing()) return; - } profile_bubble_ = - new ProfileChooserView(anchor_view, browser, view_mode, tutorial_mode, + new ProfileChooserView(anchor_view, browser, view_mode, manage_accounts_params.service_type, access_point); views::Widget* widget = views::BubbleDialogDelegateView::CreateBubble(profile_bubble_); @@ -553,13 +547,11 @@ ProfileChooserView::ProfileChooserView(views::View* anchor_view, Browser* browser, profiles::BubbleViewMode view_mode, - profiles::TutorialMode tutorial_mode, signin::GAIAServiceType service_type, signin_metrics::AccessPoint access_point) : BubbleDialogDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT), browser_(browser), view_mode_(view_mode), - tutorial_mode_(tutorial_mode), gaia_service_type_(service_type), access_point_(access_point) { // The sign in webview will be clipped on the bottom corners without these @@ -580,12 +572,6 @@ open_other_profile_indexes_map_.clear(); delete_account_button_map_.clear(); reauth_account_button_map_.clear(); - tutorial_sync_settings_ok_button_ = nullptr; - tutorial_close_button_ = nullptr; - tutorial_sync_settings_link_ = nullptr; - tutorial_see_whats_new_button_ = nullptr; - tutorial_not_you_link_ = nullptr; - tutorial_learn_more_link_ = nullptr; sync_error_signin_button_ = nullptr; sync_error_passphrase_button_ = nullptr; sync_error_upgrade_button_ = nullptr; @@ -739,9 +725,6 @@ sub_view = CreateProfileChooserView(avatar_menu); break; } - // Clears tutorial mode for all non-profile-chooser views. - if (view_mode_ != profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER) - tutorial_mode_ = profiles::TUTORIAL_MODE_NONE; layout->StartRow(1, 0); layout->AddView(sub_view); @@ -773,11 +756,6 @@ void ProfileChooserView::WindowClosing() { DCHECK_EQ(profile_bubble_, this); profile_bubble_ = NULL; - - if (tutorial_mode_ == profiles::TUTORIAL_MODE_CONFIRM_SIGNIN) { - LoginUIServiceFactory::GetForProfile(browser_->profile())-> - SyncConfirmationUIClosed(LoginUIService::SYNC_WITH_DEFAULT_SETTINGS); - } } bool ProfileChooserView::AcceleratorPressed( @@ -819,7 +797,6 @@ profiles::CloseGuestProfileWindows(); } else { UserManager::Show(base::FilePath(), - profiles::USER_MANAGER_NO_TUTORIAL, profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); } PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_OPEN_USER_MANAGER); @@ -849,22 +826,6 @@ ShowViewFromMode(profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN); } else if (sender == sync_error_signout_button_) { chrome::ShowSettingsSubPage(browser_, chrome::kSignOutSubPage); - } else if (sender == tutorial_sync_settings_ok_button_) { - LoginUIServiceFactory::GetForProfile(browser_->profile())-> - SyncConfirmationUIClosed(LoginUIService::SYNC_WITH_DEFAULT_SETTINGS); - DismissTutorial(); - ProfileMetrics::LogProfileNewAvatarMenuSignin( - ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_OK); - } else if (sender == tutorial_close_button_) { - DCHECK(tutorial_mode_ != profiles::TUTORIAL_MODE_NONE && - tutorial_mode_ != profiles::TUTORIAL_MODE_CONFIRM_SIGNIN); - DismissTutorial(); - } else if (sender == tutorial_see_whats_new_button_) { - ProfileMetrics::LogProfileNewAvatarMenuUpgrade( - ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_WHATS_NEW); - UserManager::Show(base::FilePath(), - profiles::USER_MANAGER_TUTORIAL_OVERVIEW, - profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); } else if (sender == remove_account_button_) { RemoveAccount(); } else if (sender == account_removal_cancel_button_) { @@ -896,7 +857,6 @@ ProfileMetrics::LogProfileNewAvatarMenuNotYou( ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_ADD_PERSON); UserManager::Show(base::FilePath(), - profiles::USER_MANAGER_NO_TUTORIAL, profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); } else if (sender == disconnect_button_) { ProfileMetrics::LogProfileNewAvatarMenuNotYou( @@ -957,19 +917,6 @@ } else if (sender == add_account_link_) { ShowViewFromMode(profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT); PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_ADD_ACCT); - } else if (sender == tutorial_sync_settings_link_) { - LoginUIServiceFactory::GetForProfile(browser_->profile())-> - SyncConfirmationUIClosed(LoginUIService::CONFIGURE_SYNC_FIRST); - tutorial_mode_ = profiles::TUTORIAL_MODE_NONE; - ProfileMetrics::LogProfileNewAvatarMenuSignin( - ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_SETTINGS); - } else if (sender == tutorial_not_you_link_) { - ProfileMetrics::LogProfileNewAvatarMenuUpgrade( - ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_NOT_YOU); - ShowViewFromMode(profiles::BUBBLE_VIEW_MODE_SWITCH_USER); - } else { - DCHECK(sender == tutorial_learn_more_link_); - signin_ui_util::ShowSigninErrorLearnMorePage(browser_->profile()); } } @@ -985,7 +932,6 @@ views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth); // Separate items into active and alternatives. Indexes other_profiles; - views::View* tutorial_view = NULL; views::View* sync_error_view = NULL; views::View* current_profile_view = NULL; views::View* current_profile_accounts = NULL; @@ -1005,14 +951,6 @@ } } - if (tutorial_view) { - // TODO(mlerman): update UMA stats for the new tutorial. - layout->StartRow(1, 0); - layout->AddView(tutorial_view); - } else { - tutorial_mode_ = profiles::TUTORIAL_MODE_NONE; - } - if (sync_error_view) { layout->StartRow(1, 0); layout->AddView(sync_error_view); @@ -1052,171 +990,6 @@ return view; } -void ProfileChooserView::DismissTutorial() { - // Never shows the upgrade tutorial again if manually closed. - if (tutorial_mode_ == profiles::TUTORIAL_MODE_WELCOME_UPGRADE) { - browser_->profile()->GetPrefs()->SetInteger( - prefs::kProfileAvatarTutorialShown, - signin_ui_util::kUpgradeWelcomeTutorialShowMax + 1); - } - - tutorial_mode_ = profiles::TUTORIAL_MODE_NONE; - ShowViewFromMode(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER); -} - -views::View* ProfileChooserView::CreateTutorialViewIfNeeded( - const AvatarMenu::Item& item) { - if (tutorial_mode_ == profiles::TUTORIAL_MODE_CONFIRM_SIGNIN) - return CreateSigninConfirmationView(); - - if (tutorial_mode_ == profiles::TUTORIAL_MODE_SHOW_ERROR) - return CreateSigninErrorView(); - - if (profiles::ShouldShowWelcomeUpgradeTutorial( - browser_->profile(), tutorial_mode_)) { - if (tutorial_mode_ != profiles::TUTORIAL_MODE_WELCOME_UPGRADE) { - Profile* profile = browser_->profile(); - const int show_count = profile->GetPrefs()->GetInteger( - prefs::kProfileAvatarTutorialShown); - profile->GetPrefs()->SetInteger( - prefs::kProfileAvatarTutorialShown, show_count + 1); - } - - return CreateWelcomeUpgradeTutorialView(item); - } - - return nullptr; -} - -views::View* ProfileChooserView::CreateTutorialView( - profiles::TutorialMode tutorial_mode, - const base::string16& title_text, - const base::string16& content_text, - const base::string16& link_text, - const base::string16& button_text, - bool stack_button, - views::Link** link, - views::LabelButton** button, - views::ImageButton** close_button) { - tutorial_mode_ = tutorial_mode; - - // TODO(ananta) - // Use the dialog framework to create a dialog here instead of manually - // creating one. - ChromeLayoutProvider* provider = ChromeLayoutProvider::Get(); - - views::View* view = new views::View(); - view->set_background(views::Background::CreateSolidBackground( - profiles::kAvatarTutorialBackgroundColor)); - - gfx::Insets dialog_insets = provider->GetInsetsMetric( - views::INSETS_DIALOG_CONTENTS); - - view->SetBorder(views::CreateEmptyBorder(dialog_insets)); - - // TODO(ananta) - // This seems to add a double margin at the side. Investigate and remove if - // so. - views::GridLayout* layout = CreateSingleColumnLayout( - view, kFixedMenuWidth - dialog_insets.width()); - - // Creates a second column set for buttons and links. - views::ColumnSet* button_columns = layout->AddColumnSet(1); - button_columns->AddColumn(views::GridLayout::LEADING, - views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0); - button_columns->AddPaddingColumn(1, - provider->GetDistanceMetric(DISTANCE_UNRELATED_CONTROL_HORIZONTAL)); - button_columns->AddColumn(views::GridLayout::TRAILING, - views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0); - - // Adds title and close button if needed. - const SkColor kTitleAndButtonTextColor = SK_ColorWHITE; - views::Label* title_label = new views::Label(title_text); - title_label->SetMultiLine(true); - title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); - title_label->SetAutoColorReadabilityEnabled(false); - title_label->SetEnabledColor(kTitleAndButtonTextColor); - title_label->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList( - ui::ResourceBundle::MediumFont)); - - if (close_button) { - layout->StartRow(1, 1); - layout->AddView(title_label); - *close_button = new views::ImageButton(this); - (*close_button)->SetImageAlignment(views::ImageButton::ALIGN_RIGHT, - views::ImageButton::ALIGN_MIDDLE); - ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); - (*close_button)->SetImage(views::ImageButton::STATE_NORMAL, - rb->GetImageSkiaNamed(IDR_CLOSE_1)); - (*close_button)->SetImage(views::ImageButton::STATE_HOVERED, - rb->GetImageSkiaNamed(IDR_CLOSE_1_H)); - (*close_button)->SetImage(views::ImageButton::STATE_PRESSED, - rb->GetImageSkiaNamed(IDR_CLOSE_1_P)); - layout->AddView(*close_button); - } else { - layout->StartRow(1, 0); - layout->AddView(title_label); - } - - // Adds body content. - views::Label* content_label = new views::Label(content_text); - content_label->SetMultiLine(true); - content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); - content_label->SetAutoColorReadabilityEnabled(false); - content_label->SetEnabledColor(profiles::kAvatarTutorialContentTextColor); - - const int related_control_vertical = - provider->GetDistanceMetric(DISTANCE_UNRELATED_CONTROL_VERTICAL); - - layout->StartRowWithPadding(1, 0, 0, related_control_vertical); - layout->AddView(content_label); - - // Adds links and buttons. - bool has_button = !button_text.empty(); - if (has_button) { - *button = views::MdTextButton::CreateSecondaryUiButton(this, button_text); - if (ui::MaterialDesignController::IsSecondaryUiMaterial()) - (*button)->SetEnabledTextColors(kTitleAndButtonTextColor); - else - (*button)->SetHorizontalAlignment(gfx::ALIGN_CENTER); - } - - bool has_link = !link_text.empty(); - if (has_link) { - *link = CreateLink(link_text, this); - (*link)->SetHorizontalAlignment(gfx::ALIGN_LEFT); - (*link)->SetAutoColorReadabilityEnabled(false); - (*link)->SetEnabledColor(kTitleAndButtonTextColor); - } - - const int unrelated_control_vertical = - provider->GetDistanceMetric(DISTANCE_UNRELATED_CONTROL_VERTICAL); - - if (stack_button) { - DCHECK(has_button); - layout->StartRowWithPadding(1, 0, 0, unrelated_control_vertical); - layout->AddView(*button); - if (has_link) { - layout->StartRowWithPadding(1, 0, 0, related_control_vertical); - (*link)->SetHorizontalAlignment(gfx::ALIGN_CENTER); - layout->AddView(*link); - } - } else { - DCHECK(has_link || has_button); - layout->StartRowWithPadding(1, 1, 0, unrelated_control_vertical); - if (has_link) - layout->AddView(*link); - else - layout->SkipColumns(1); - if (has_button) - layout->AddView(*button); - else - layout->SkipColumns(1); - } - - return view; -} - views::View* ProfileChooserView::CreateSyncErrorViewIfNeeded() { int content_string_id, button_string_id; views::LabelButton** button_out = nullptr; @@ -1787,63 +1560,6 @@ kFixedAccountRemovalViewWidth); } -views::View* ProfileChooserView::CreateWelcomeUpgradeTutorialView( - const AvatarMenu::Item& avatar_item) { - ProfileMetrics::LogProfileNewAvatarMenuUpgrade( - ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_VIEW); - - // For local profiles, the "Not you" link doesn't make sense. - base::string16 link_message = avatar_item.signed_in ? - l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU, avatar_item.name) : - base::string16(); - - return CreateTutorialView( - profiles::TUTORIAL_MODE_WELCOME_UPGRADE, - l10n_util::GetStringUTF16( - IDS_PROFILES_WELCOME_UPGRADE_TUTORIAL_TITLE), - l10n_util::GetStringUTF16( - IDS_PROFILES_WELCOME_UPGRADE_TUTORIAL_CONTENT_TEXT), - link_message, - l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_WHATS_NEW_BUTTON), - true /* stack_button */, - &tutorial_not_you_link_, - &tutorial_see_whats_new_button_, - &tutorial_close_button_); -} - -views::View* ProfileChooserView::CreateSigninConfirmationView() { - ProfileMetrics::LogProfileNewAvatarMenuSignin( - ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_VIEW); - - return CreateTutorialView( - profiles::TUTORIAL_MODE_CONFIRM_SIGNIN, - l10n_util::GetStringUTF16(IDS_PROFILES_CONFIRM_SIGNIN_TUTORIAL_TITLE), - l10n_util::GetStringUTF16( - IDS_PROFILES_CONFIRM_SIGNIN_TUTORIAL_CONTENT_TEXT), - l10n_util::GetStringUTF16(IDS_PROFILES_SYNC_SETTINGS_LINK), - l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_OK_BUTTON), - false /* stack_button */, - &tutorial_sync_settings_link_, - &tutorial_sync_settings_ok_button_, - NULL /* close_button*/); -} - -views::View* ProfileChooserView::CreateSigninErrorView() { - LoginUIService* login_ui_service = - LoginUIServiceFactory::GetForProfile(browser_->profile()); - base::string16 last_login_result(login_ui_service->GetLastLoginResult()); - return CreateTutorialView( - profiles::TUTORIAL_MODE_SHOW_ERROR, - l10n_util::GetStringUTF16(IDS_PROFILES_ERROR_TUTORIAL_TITLE), - last_login_result, - l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_TUTORIAL_LEARN_MORE), - base::string16(), - false /* stack_button */, - &tutorial_learn_more_link_, - NULL, - &tutorial_close_button_); -} - views::View* ProfileChooserView::CreateSwitchUserView() { ChromeLayoutProvider* provider = ChromeLayoutProvider::Get(); views::View* view = new views::View();
diff --git a/chrome/browser/ui/views/profiles/profile_chooser_view.h b/chrome/browser/ui/views/profiles/profile_chooser_view.h index 1bb9cc9..72fcf29c 100644 --- a/chrome/browser/ui/views/profiles/profile_chooser_view.h +++ b/chrome/browser/ui/views/profiles/profile_chooser_view.h
@@ -50,7 +50,6 @@ // the existing bubble will auto-close due to focus loss. static void ShowBubble( profiles::BubbleViewMode view_mode, - profiles::TutorialMode tutorial_mode, const signin::ManageAccountsParams& manage_accounts_params, signin_metrics::AccessPoint access_point, views::View* anchor_view, @@ -72,7 +71,6 @@ ProfileChooserView(views::View* anchor_view, Browser* browser, profiles::BubbleViewMode view_mode, - profiles::TutorialMode tutorial_mode, signin::GAIAServiceType service_type, signin_metrics::AccessPoint access_point); ~ProfileChooserView() override; @@ -152,40 +150,6 @@ // Removes the currently selected account and attempts to restart Chrome. void RemoveAccount(); - // Close the tutorial card. - void DismissTutorial(); - - // Creates a tutorial card to introduce an upgrade user to the new avatar - // menu. |avatar_item| refers to the current profile. - views::View* CreateWelcomeUpgradeTutorialView( - const AvatarMenu::Item& avatar_item); - - // Creates a tutorial card to have the user confirm the last Chrome signin, - // Chrome sync will be delayed until the user either dismisses the tutorial, - // or configures sync through the "Settings" link. - views::View* CreateSigninConfirmationView(); - - // Creates a tutorial card to show the errors in the last Chrome signin. - views::View* CreateSigninErrorView(); - - views::View* CreateTutorialViewIfNeeded(const AvatarMenu::Item& item); - - // Creates a tutorial card. If |stack_button| is true, places the button above - // the link otherwise places both on the same row with the link left aligned - // and button right aligned. The method sets |link| to point to the newly - // create link, |button| to the newly created button, and |tutorial_mode_| to - // the given |tutorial_mode|. - views::View* CreateTutorialView( - profiles::TutorialMode tutorial_mode, - const base::string16& title_text, - const base::string16& content_text, - const base::string16& link_text, - const base::string16& button_text, - bool stack_button, - views::Link** link, - views::LabelButton** button, - views::ImageButton** close_button); - // Creates a header for signin and sync error surfacing for the user menu. views::View* CreateSyncErrorViewIfNeeded(); @@ -208,14 +172,6 @@ AccountButtonIndexes delete_account_button_map_; AccountButtonIndexes reauth_account_button_map_; - // Links and buttons displayed in the tutorial card. - views::LabelButton* tutorial_sync_settings_ok_button_; - views::Link* tutorial_sync_settings_link_; - views::LabelButton* tutorial_see_whats_new_button_; - views::Link* tutorial_not_you_link_; - views::Link* tutorial_learn_more_link_; - views::ImageButton* tutorial_close_button_; - // Buttons in the signin/sync error header on top of the desktop user menu. views::LabelButton* sync_error_signin_button_; views::LabelButton* sync_error_passphrase_button_; @@ -260,9 +216,6 @@ // Active view mode. profiles::BubbleViewMode view_mode_; - // The current tutorial mode. - profiles::TutorialMode tutorial_mode_; - // The GAIA service type provided in the response header. signin::GAIAServiceType gaia_service_type_;
diff --git a/chrome/browser/ui/views/profiles/user_manager_view.cc b/chrome/browser/ui/views/profiles/user_manager_view.cc index 2b069658..1b55dfb8 100644 --- a/chrome/browser/ui/views/profiles/user_manager_view.cc +++ b/chrome/browser/ui/views/profiles/user_manager_view.cc
@@ -135,7 +135,6 @@ // static void UserManager::Show( const base::FilePath& profile_path_to_focus, - profiles::UserManagerTutorialMode tutorial_mode, profiles::UserManagerAction user_manager_action) { DCHECK(profile_path_to_focus != ProfileManager::GetGuestProfilePath()); @@ -165,7 +164,7 @@ UserManagerView* user_manager = new UserManagerView(); user_manager->set_user_manager_started_showing(base::Time::Now()); profiles::CreateSystemProfileForUserManager( - profile_path_to_focus, tutorial_mode, user_manager_action, + profile_path_to_focus, user_manager_action, base::Bind(&UserManagerView::OnSystemProfileCreated, base::Passed(base::WrapUnique(user_manager)), base::Owned(new base::AutoReset<bool>(
diff --git a/chrome/browser/ui/views/tab_icon_view.cc b/chrome/browser/ui/views/tab_icon_view.cc index 3b870b8..d9975ef4 100644 --- a/chrome/browser/ui/views/tab_icon_view.cc +++ b/chrome/browser/ui/views/tab_icon_view.cc
@@ -122,7 +122,7 @@ return "TabIconView"; } -void TabIconView::OnPaint(gfx::Canvas* canvas) { +void TabIconView::PaintButtonContents(gfx::Canvas* canvas) { bool rendered = false; if (model_->ShouldTabIconViewAnimate()) {
diff --git a/chrome/browser/ui/views/tab_icon_view.h b/chrome/browser/ui/views/tab_icon_view.h index 7ef95df..cc22a74 100644 --- a/chrome/browser/ui/views/tab_icon_view.h +++ b/chrome/browser/ui/views/tab_icon_view.h
@@ -34,7 +34,7 @@ // views::MenuButton: gfx::Size CalculatePreferredSize() const override; const char* GetClassName() const override; - void OnPaint(gfx::Canvas* canvas) override; + void PaintButtonContents(gfx::Canvas* canvas) override; void PaintThrobber(gfx::Canvas* canvas); void PaintFavicon(gfx::Canvas* canvas, const gfx::ImageSkia& image);
diff --git a/chrome/browser/ui/views/tabs/alert_indicator_button.cc b/chrome/browser/ui/views/tabs/alert_indicator_button.cc index 0a7f1e65..9f1fd4c 100644 --- a/chrome/browser/ui/views/tabs/alert_indicator_button.cc +++ b/chrome/browser/ui/views/tabs/alert_indicator_button.cc
@@ -216,22 +216,6 @@ UpdateEnabledForMuteToggle(); } -void AlertIndicatorButton::OnPaint(gfx::Canvas* canvas) { - double opaqueness = 1.0; - if (fade_animation_) { - opaqueness = fade_animation_->GetCurrentValue(); - if (alert_state_ == TabAlertState::NONE) - opaqueness = 1.0 - opaqueness; // Fading out, not in. - } else if (is_dormant()) { - opaqueness = 0.5; - } - if (opaqueness < 1.0) - canvas->SaveLayerAlpha(opaqueness * SK_AlphaOPAQUE); - ImageButton::OnPaint(canvas); - if (opaqueness < 1.0) - canvas->Restore(); -} - bool AlertIndicatorButton::DoesIntersectRect(const views::View* target, const gfx::Rect& rect) const { // If this button is not enabled, Tab (the parent View) handles all mouse @@ -282,6 +266,22 @@ return views::ImageButton::IsTriggerableEvent(event); } +void AlertIndicatorButton::PaintButtonContents(gfx::Canvas* canvas) { + double opaqueness = 1.0; + if (fade_animation_) { + opaqueness = fade_animation_->GetCurrentValue(); + if (alert_state_ == TabAlertState::NONE) + opaqueness = 1.0 - opaqueness; // Fading out, not in. + } else if (is_dormant()) { + opaqueness = 0.5; + } + if (opaqueness < 1.0) + canvas->SaveLayerAlpha(opaqueness * SK_AlphaOPAQUE); + ImageButton::PaintButtonContents(canvas); + if (opaqueness < 1.0) + canvas->Restore(); +} + gfx::ImageSkia AlertIndicatorButton::GetImageToPaint() { if (is_dormant()) return views::ImageButton::images_[views::CustomButton::STATE_NORMAL];
diff --git a/chrome/browser/ui/views/tabs/alert_indicator_button.h b/chrome/browser/ui/views/tabs/alert_indicator_button.h index ba0effe..1dbed5a8 100644 --- a/chrome/browser/ui/views/tabs/alert_indicator_button.h +++ b/chrome/browser/ui/views/tabs/alert_indicator_button.h
@@ -68,7 +68,6 @@ void OnMouseExited(const ui::MouseEvent& event) override; void OnMouseMoved(const ui::MouseEvent& event) override; void OnBoundsChanged(const gfx::Rect& previous_bounds) override; - void OnPaint(gfx::Canvas* canvas) override; // views::ViewTargeterDelegate bool DoesIntersectRect(const View* target, @@ -79,6 +78,7 @@ // views::CustomButton: bool IsTriggerableEvent(const ui::Event& event) override; + void PaintButtonContents(gfx::Canvas* canvas) override; // views::ImageButton: gfx::ImageSkia GetImageToPaint() override;
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc index 6c5a019..fcac8658 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.cc +++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -263,8 +263,8 @@ /////////////////////////////////////////////////////////////////////////////// // NewTabButton // -// A subclass of button that hit-tests to the shape of the new tab button and -// does custom drawing. +// A subclass of ImageButton that hit-tests to the shape of the new tab button +// and does custom drawing. class NewTabButton : public views::ImageButton, public views::MaskedTargeterDelegate { @@ -284,7 +284,7 @@ void OnMouseReleased(const ui::MouseEvent& event) override; #endif void OnGestureEvent(ui::GestureEvent* event) override; - void OnPaint(gfx::Canvas* canvas) override; + void PaintButtonContents(gfx::Canvas* canvas) override; // views::MaskedTargeterDelegate: bool GetHitTestMask(gfx::Path* mask) const override; @@ -361,7 +361,7 @@ event->SetHandled(); } -void NewTabButton::OnPaint(gfx::Canvas* canvas) { +void NewTabButton::PaintButtonContents(gfx::Canvas* canvas) { gfx::ScopedCanvas scoped_canvas(canvas); const int visible_height = GetLayoutSize(NEW_TAB_BUTTON).height(); canvas->Translate(gfx::Vector2d(0, height() - visible_height));
diff --git a/chrome/browser/ui/views/toolbar/app_menu_button.cc b/chrome/browser/ui/views/toolbar/app_menu_button.cc index f2cd131..461e0ac 100644 --- a/chrome/browser/ui/views/toolbar/app_menu_button.cc +++ b/chrome/browser/ui/views/toolbar/app_menu_button.cc
@@ -143,9 +143,9 @@ views::MenuButton::Layout(); } -void AppMenuButton::OnPaint(gfx::Canvas* canvas) { +void AppMenuButton::PaintButtonContents(gfx::Canvas* canvas) { if (!animation_) { - views::MenuButton::OnPaint(canvas); + views::MenuButton::PaintButtonContents(canvas); return; }
diff --git a/chrome/browser/ui/views/toolbar/app_menu_button.h b/chrome/browser/ui/views/toolbar/app_menu_button.h index 037081b3..804c5f6 100644 --- a/chrome/browser/ui/views/toolbar/app_menu_button.h +++ b/chrome/browser/ui/views/toolbar/app_menu_button.h
@@ -58,7 +58,7 @@ // views::MenuButton: gfx::Size CalculatePreferredSize() const override; void Layout() override; - void OnPaint(gfx::Canvas* canvas) override; + void PaintButtonContents(gfx::Canvas* canvas) override; // TabStripObserver: void TabInsertedAt(TabStripModel* tab_strip_model,
diff --git a/chrome/browser/ui/webui/options/certificate_manager_browsertest.js b/chrome/browser/ui/webui/options/certificate_manager_browsertest.js index cb9e3d81..0db9129 100644 --- a/chrome/browser/ui/webui/options/certificate_manager_browsertest.js +++ b/chrome/browser/ui/webui/options/certificate_manager_browsertest.js
@@ -248,7 +248,7 @@ 'policy': false }], }], ] - ].forEach(CertificateManager.onPopulateTree)})); + ].forEach(CertificateManager.onPopulateTree);})); }, };
diff --git a/chrome/browser/ui/webui/profile_helper.cc b/chrome/browser/ui/webui/profile_helper.cc index 528292e..968b967 100644 --- a/chrome/browser/ui/webui/profile_helper.cc +++ b/chrome/browser/ui/webui/profile_helper.cc
@@ -27,7 +27,7 @@ void ShowUserManager(const ProfileManager::CreateCallback& callback) { if (!UserManager::IsShowing()) { - UserManager::Show(base::FilePath(), profiles::USER_MANAGER_NO_TUTORIAL, + UserManager::Show(base::FilePath(), profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); }
diff --git a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc index 2d1181a..cd129cb 100644 --- a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
@@ -45,6 +45,14 @@ namespace { +// These values are written to logs. New enum values can be added, but existing +// enums must never be renumbered or deleted and reused. +enum PpdSourceForHistogram { kUser = 0, kScs = 1, kPpdSourceMax }; + +void RecordPpdSource(const PpdSourceForHistogram& source) { + UMA_HISTOGRAM_ENUMERATION("Printing.CUPS.PpdSource", source, kPpdSourceMax); +} + void OnRemovedPrinter(bool success) {} std::unique_ptr<base::DictionaryValue> GetPrinterInfo(const Printer& printer) { @@ -226,6 +234,7 @@ // Verify a valid ppd path is present. if (!printer_ppd_path.empty()) { + RecordPpdSource(kUser); GURL tmp = net::FilePathToFileURL(base::FilePath(printer_ppd_path)); if (!tmp.is_valid()) { LOG(ERROR) << "Invalid ppd path: " << printer_ppd_path; @@ -234,6 +243,7 @@ } printer->mutable_ppd_reference()->user_supplied_ppd_url = tmp.spec(); } else if (!printer_manufacturer.empty() && !printer_model.empty()) { + RecordPpdSource(kScs); // Using the manufacturer and model, get a ppd reference. if (!ppd_provider_->GetPpdReference(printer_manufacturer, printer_model, printer->mutable_ppd_reference())) { @@ -256,6 +266,8 @@ std::unique_ptr<Printer> printer, chromeos::PrinterSetupResult result_code) { std::string printer_name = printer->display_name(); + UMA_HISTOGRAM_ENUMERATION("Printing.CUPS.PrinterSetupResult", result_code, + chromeos::PrinterSetupResult::kMaxValue); switch (result_code) { case chromeos::PrinterSetupResult::kSuccess: { auto* manager = PrintersManagerFactory::GetForBrowserContext(profile_);
diff --git a/chrome/browser/ui/webui/settings/people_handler.cc b/chrome/browser/ui/webui/settings/people_handler.cc index 4c37c95..edd8e44 100644 --- a/chrome/browser/ui/webui/settings/people_handler.cc +++ b/chrome/browser/ui/webui/settings/people_handler.cc
@@ -557,7 +557,7 @@ } void PeopleHandler::HandleManageOtherPeople(const base::ListValue* /* args */) { - UserManager::Show(base::FilePath(), profiles::USER_MANAGER_NO_TUTORIAL, + UserManager::Show(base::FilePath(), profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 56b69361..cd80d9b 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -5026,6 +5026,9 @@ "$root_out_dir/resources.pak", ] } + if (is_mac) { + deps += [ "//chrome:chrome_app" ] + } # This target should not require the Chrome executable to run. assert_no_deps = [ "//chrome" ]
diff --git a/chrome/test/perf/mach_ports_performancetest.cc b/chrome/test/perf/mach_ports_performancetest.cc index 7887298a..e7b1d78 100644 --- a/chrome/test/perf/mach_ports_performancetest.cc +++ b/chrome/test/perf/mach_ports_performancetest.cc
@@ -25,13 +25,13 @@ class MachPortsTest : public InProcessBrowserTest { public: MachPortsTest() { - server_.ServeFilesFromSourceDirectory("data/mach_ports/moz"); + embedded_test_server()->ServeFilesFromSourceDirectory( + "data/mach_ports/moz"); } - void SetUp() override { - InProcessBrowserTest::SetUp(); - - ASSERT_TRUE(server_.Start()); + void SetUpOnMainThread() override { + InProcessBrowserTest::SetUpOnMainThread(); + ASSERT_TRUE(embedded_test_server()->Start()); } void TearDown() override { @@ -72,12 +72,12 @@ // Adds a tab from the page cycler data at the specified domain. void AddTab(const std::string& domain) { - GURL url = server_.GetURL("/" + domain + "/").Resolve("?skip"); - AddTabAtIndex(0, url, ui::PAGE_TRANSITION_TYPED); + AddTabAtIndex( + 0, embedded_test_server()->GetURL("/" + domain + "/").Resolve("?skip"), + ui::PAGE_TRANSITION_TYPED); } private: - net::EmbeddedTestServer server_; std::vector<int> port_counts_; };
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc index f4700d5..e8824c4 100644 --- a/chromecast/browser/cast_content_browser_client.cc +++ b/chromecast/browser/cast_content_browser_client.cc
@@ -37,7 +37,7 @@ #include "chromecast/browser/url_request_context_factory.h" #include "chromecast/common/global_descriptors.h" #include "chromecast/media/audio/cast_audio_manager.h" -#include "chromecast/media/cma/backend/media_pipeline_backend_factory.h" +#include "chromecast/media/cma/backend/media_pipeline_backend_factory_impl.h" #include "chromecast/media/cma/backend/media_pipeline_backend_manager.h" #include "chromecast/public/media/media_pipeline_backend.h" #include "components/crash/content/app/breakpad_linux.h" @@ -177,7 +177,7 @@ DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); if (!media_pipeline_backend_factory_) { media_pipeline_backend_factory_.reset( - new media::MediaPipelineBackendFactory( + new media::MediaPipelineBackendFactoryImpl( media_pipeline_backend_manager())); } return media_pipeline_backend_factory_.get(); @@ -197,9 +197,15 @@ std::unique_ptr<::media::AudioManager> CastContentBrowserClient::CreateAudioManager( ::media::AudioLogFactory* audio_log_factory) { + // TODO(alokp): Consider switching off the mixer on audio platforms + // because we already have a mixer in the audio pipeline downstream of + // CastAudioManager. + bool use_mixer = true; return base::MakeUnique<media::CastAudioManager>( base::MakeUnique<::media::AudioThreadImpl>(), audio_log_factory, - media_pipeline_backend_manager()); + base::MakeUnique<media::MediaPipelineBackendFactoryImpl>( + media_pipeline_backend_manager()), + GetMediaTaskRunner(), use_mixer); } std::unique_ptr<::media::CdmFactory>
diff --git a/chromecast/media/BUILD.gn b/chromecast/media/BUILD.gn index 698f77f5..896700bdd 100644 --- a/chromecast/media/BUILD.gn +++ b/chromecast/media/BUILD.gn
@@ -16,6 +16,7 @@ test("cast_media_unittests") { sources = [ + "audio/cast_audio_manager_unittest.cc", "audio/cast_audio_mixer_unittest.cc", "audio/cast_audio_output_stream_unittest.cc", "base/media_resource_tracker_unittest.cc", @@ -29,6 +30,7 @@ "//base/test:test_support", "//chromecast/base", "//chromecast/base/metrics:test_support", + "//chromecast/media/cma:test_support", "//chromecast/public", "//media", "//media/audio:test_support",
diff --git a/chromecast/media/audio/cast_audio_manager.cc b/chromecast/media/audio/cast_audio_manager.cc index 2176cddc..3cd80d6f 100644 --- a/chromecast/media/audio/cast_audio_manager.cc +++ b/chromecast/media/audio/cast_audio_manager.cc
@@ -8,9 +8,11 @@ #include <string> #include "base/bind.h" +#include "base/memory/ptr_util.h" #include "chromecast/media/audio/cast_audio_mixer.h" #include "chromecast/media/audio/cast_audio_output_stream.h" -#include "chromecast/media/cma/backend/media_pipeline_backend_manager.h" +#include "chromecast/media/cma/backend/media_pipeline_backend_factory.h" +#include "chromecast/public/media/media_pipeline_backend.h" namespace { // TODO(alokp): Query the preferred value from media backend. @@ -30,22 +32,15 @@ CastAudioManager::CastAudioManager( std::unique_ptr<::media::AudioThread> audio_thread, ::media::AudioLogFactory* audio_log_factory, - MediaPipelineBackendManager* backend_manager) - : CastAudioManager(std::move(audio_thread), - audio_log_factory, - backend_manager, - new CastAudioMixer( - base::Bind(&CastAudioManager::MakeMixerOutputStream, - base::Unretained(this)))) {} - -CastAudioManager::CastAudioManager( - std::unique_ptr<::media::AudioThread> audio_thread, - ::media::AudioLogFactory* audio_log_factory, - MediaPipelineBackendManager* backend_manager, - CastAudioMixer* audio_mixer) + std::unique_ptr<MediaPipelineBackendFactory> backend_factory, + scoped_refptr<base::SingleThreadTaskRunner> backend_task_runner, + bool use_mixer) : AudioManagerBase(std::move(audio_thread), audio_log_factory), - backend_manager_(backend_manager), - mixer_(audio_mixer) {} + backend_factory_(std::move(backend_factory)), + backend_task_runner_(std::move(backend_task_runner)) { + if (use_mixer) + mixer_ = base::MakeUnique<CastAudioMixer>(this); +} CastAudioManager::~CastAudioManager() = default; @@ -80,12 +75,6 @@ return "Cast"; } -std::unique_ptr<MediaPipelineBackend> -CastAudioManager::CreateMediaPipelineBackend( - const MediaPipelineDeviceParams& params) { - return backend_manager_->CreateMediaPipelineBackend(params); -} - void CastAudioManager::ReleaseOutputStream(::media::AudioOutputStream* stream) { // If |stream| is |mixer_output_stream_|, we should not use // AudioManagerBase::ReleaseOutputStream as we do not want the release @@ -108,7 +97,7 @@ // If |mixer_| exists, return a mixing stream. if (mixer_) - return mixer_->MakeStream(params, this); + return mixer_->MakeStream(params); else return new CastAudioOutputStream(params, this); } @@ -121,7 +110,7 @@ // If |mixer_| exists, return a mixing stream. if (mixer_) - return mixer_->MakeStream(params, this); + return mixer_->MakeStream(params); else return new CastAudioOutputStream(params, this); }
diff --git a/chromecast/media/audio/cast_audio_manager.h b/chromecast/media/audio/cast_audio_manager.h index f12264a..7c95557 100644 --- a/chromecast/media/audio/cast_audio_manager.h +++ b/chromecast/media/audio/cast_audio_manager.h
@@ -13,22 +13,19 @@ namespace media { class CastAudioMixer; -class MediaPipelineBackend; -class MediaPipelineBackendManager; -struct MediaPipelineDeviceParams; +class MediaPipelineBackendFactory; class CastAudioManager : public ::media::AudioManagerBase { public: - CastAudioManager(std::unique_ptr<::media::AudioThread> audio_thread, - ::media::AudioLogFactory* audio_log_factory, - MediaPipelineBackendManager* backend_manager); - CastAudioManager(std::unique_ptr<::media::AudioThread> audio_thread, - ::media::AudioLogFactory* audio_log_factory, - MediaPipelineBackendManager* backend_manager, - CastAudioMixer* audio_mixer); + CastAudioManager( + std::unique_ptr<::media::AudioThread> audio_thread, + ::media::AudioLogFactory* audio_log_factory, + std::unique_ptr<MediaPipelineBackendFactory> backend_factory, + scoped_refptr<base::SingleThreadTaskRunner> backend_task_runner, + bool use_mixer); ~CastAudioManager() override; - // AudioManager implementation. + // AudioManagerBase implementation. bool HasAudioOutputDevices() override; bool HasAudioInputDevices() override; void ShowAudioInputSettings() override; @@ -37,15 +34,16 @@ ::media::AudioParameters GetInputStreamParameters( const std::string& device_id) override; const char* GetName() override; - - // AudioManagerBase implementation void ReleaseOutputStream(::media::AudioOutputStream* stream) override; - // This must be called on audio thread. - virtual std::unique_ptr<MediaPipelineBackend> CreateMediaPipelineBackend( - const MediaPipelineDeviceParams& params); + MediaPipelineBackendFactory* backend_factory() { + return backend_factory_.get(); + } + base::SingleThreadTaskRunner* backend_task_runner() { + return backend_task_runner_.get(); + } - private: + protected: // AudioManagerBase implementation. ::media::AudioOutputStream* MakeLinearOutputStream( const ::media::AudioParameters& params, @@ -67,13 +65,16 @@ const ::media::AudioParameters& input_params) override; // Generates a CastAudioOutputStream for |mixer_|. - ::media::AudioOutputStream* MakeMixerOutputStream( + virtual ::media::AudioOutputStream* MakeMixerOutputStream( const ::media::AudioParameters& params); - MediaPipelineBackendManager* const backend_manager_; + private: + friend class CastAudioMixer; + + std::unique_ptr<MediaPipelineBackendFactory> backend_factory_; + scoped_refptr<base::SingleThreadTaskRunner> backend_task_runner_; std::unique_ptr<::media::AudioOutputStream> mixer_output_stream_; std::unique_ptr<CastAudioMixer> mixer_; - DISALLOW_COPY_AND_ASSIGN(CastAudioManager); };
diff --git a/chromecast/media/audio/cast_audio_manager_unittest.cc b/chromecast/media/audio/cast_audio_manager_unittest.cc new file mode 100644 index 0000000..ef8ea959 --- /dev/null +++ b/chromecast/media/audio/cast_audio_manager_unittest.cc
@@ -0,0 +1,78 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/media/audio/cast_audio_manager.h" + +#include "base/memory/ptr_util.h" +#include "base/test/test_message_loop.h" +#include "chromecast/media/cma/test/mock_media_pipeline_backend.h" +#include "chromecast/media/cma/test/mock_media_pipeline_backend_factory.h" +#include "media/audio/fake_audio_log_factory.h" +#include "media/audio/test_audio_thread.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; +using testing::Invoke; +using testing::Return; +using testing::StrictMock; + +namespace chromecast { +namespace media { +namespace { + +const ::media::AudioParameters kDefaultAudioParams( + ::media::AudioParameters::AUDIO_PCM_LOW_LATENCY, + ::media::CHANNEL_LAYOUT_STEREO, + ::media::AudioParameters::kAudioCDSampleRate, + 16, + 256); + +class CastAudioManagerTest : public testing::Test { + public: + CastAudioManagerTest() : media_thread_("CastMediaThread") { + CHECK(media_thread_.Start()); + + backend_factory_ = new MockMediaPipelineBackendFactory(); + audio_manager_ = base::MakeUnique<CastAudioManager>( + base::MakeUnique<::media::TestAudioThread>(), &audio_log_factory_, + base::WrapUnique(backend_factory_), media_thread_.task_runner(), false); + } + + ~CastAudioManagerTest() override { audio_manager_->Shutdown(); } + + protected: + base::TestMessageLoop message_loop_; + base::Thread media_thread_; + ::media::FakeAudioLogFactory audio_log_factory_; + std::unique_ptr<CastAudioManager> audio_manager_; + + // Owned by |audio_manager_| + MockMediaPipelineBackendFactory* backend_factory_; +}; + +TEST_F(CastAudioManagerTest, MakeAudioOutputStreamProxy) { + StrictMock<MockAudioDecoder> audio_decoder; + EXPECT_CALL(audio_decoder, SetDelegate(_)).Times(1); + EXPECT_CALL(audio_decoder, SetConfig(_)).WillOnce(Return(true)); + + auto backend = base::MakeUnique<StrictMock<MockMediaPipelineBackend>>(); + EXPECT_CALL(*backend, CreateAudioDecoder()).WillOnce(Return(&audio_decoder)); + EXPECT_CALL(*backend, Initialize()).WillOnce(Return(true)); + + EXPECT_CALL(*backend_factory_, CreateBackend(_)) + .WillOnce(Invoke([&backend](const MediaPipelineDeviceParams&) { + return std::move(backend); + })); + + ::media::AudioOutputStream* stream = + audio_manager_->MakeAudioOutputStreamProxy(kDefaultAudioParams, + std::string()); + EXPECT_TRUE(stream->Open()); + stream->Close(); +} + +} // namespace +} // namespace media +} // namespace chromecast
diff --git a/chromecast/media/audio/cast_audio_mixer.cc b/chromecast/media/audio/cast_audio_mixer.cc index 4d236a1..a7ed6f5 100644 --- a/chromecast/media/audio/cast_audio_mixer.cc +++ b/chromecast/media/audio/cast_audio_mixer.cc
@@ -4,7 +4,9 @@ #include "chromecast/media/audio/cast_audio_mixer.h" +#include "base/bind.h" #include "base/logging.h" +#include "base/memory/ptr_util.h" #include "chromecast/media/audio/cast_audio_manager.h" #include "chromecast/media/audio/cast_audio_output_stream.h" #include "media/base/audio_timestamp_helper.h" @@ -21,30 +23,34 @@ class CastAudioMixer::MixerProxyStream : public ::media::AudioOutputStream, - private ::media::AudioConverter::InputCallback { + public ::media::AudioConverter::InputCallback { public: MixerProxyStream(const ::media::AudioParameters& input_params, const ::media::AudioParameters& output_params, - CastAudioManager* audio_manager, CastAudioMixer* audio_mixer) - : audio_manager_(audio_manager), - audio_mixer_(audio_mixer), - source_callback_(nullptr), + : audio_mixer_(audio_mixer), input_params_(input_params), output_params_(output_params), opened_(false), - volume_(1.0) {} + volume_(1.0), + source_callback_(nullptr) { + DCHECK_CALLED_ON_VALID_THREAD(audio_thread_checker_); + } - ~MixerProxyStream() override {} + ~MixerProxyStream() override { + DCHECK_CALLED_ON_VALID_THREAD(audio_thread_checker_); + } void OnError() { - DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); - + DCHECK_CALLED_ON_VALID_THREAD(audio_thread_checker_); if (source_callback_) source_callback_->OnError(); } private: + // ResamplerProxy is an intermediate filter between MixerProxyStream and + // CastAudioMixer::output_stream_ whose only responsibility is to resample + // audio to the sample rate expected by CastAudioMixer::output_stream_. class ResamplerProxy : public ::media::AudioConverter::InputCallback { public: ResamplerProxy(::media::AudioConverter::InputCallback* input_callback, @@ -53,6 +59,7 @@ resampler_.reset( new ::media::AudioConverter(input_params, output_params, false)); resampler_->AddInput(input_callback); + DETACH_FROM_THREAD(backend_thread_checker_); } ~ResamplerProxy() override {} @@ -61,20 +68,21 @@ // ::media::AudioConverter::InputCallback implementation double ProvideInput(::media::AudioBus* audio_bus, uint32_t frames_delayed) override { + DCHECK_CALLED_ON_VALID_THREAD(backend_thread_checker_); resampler_->ConvertWithDelay(frames_delayed, audio_bus); - // Volume multiplier has already been applied by |resampler_|. return 1.0; } std::unique_ptr<::media::AudioConverter> resampler_; + THREAD_CHECKER(backend_thread_checker_); DISALLOW_COPY_AND_ASSIGN(ResamplerProxy); }; // ::media::AudioOutputStream implementation bool Open() override { - DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); + DCHECK_CALLED_ON_VALID_THREAD(audio_thread_checker_); ::media::AudioParameters::Format format = input_params_.format(); DCHECK((format == ::media::AudioParameters::AUDIO_PCM_LINEAR) || @@ -93,46 +101,52 @@ } void Close() override { - DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); + DCHECK_CALLED_ON_VALID_THREAD(audio_thread_checker_); if (proxy_) Stop(); if (opened_) audio_mixer_->Unregister(this); + // Signal to the manager that we're closed and can be removed. // This should be the last call in the function as it deletes "this". - audio_manager_->ReleaseOutputStream(this); + audio_mixer_->audio_manager_->ReleaseOutputStream(this); } void Start(AudioSourceCallback* source_callback) override { - DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); + DCHECK_CALLED_ON_VALID_THREAD(audio_thread_checker_); DCHECK(source_callback); if (!opened_ || proxy_) return; source_callback_ = source_callback; - proxy_.reset(new ResamplerProxy(this, input_params_, output_params_)); + proxy_ = + base::MakeUnique<ResamplerProxy>(this, input_params_, output_params_); audio_mixer_->AddInput(proxy_.get()); } void Stop() override { - DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); + DCHECK_CALLED_ON_VALID_THREAD(audio_thread_checker_); if (!proxy_) return; audio_mixer_->RemoveInput(proxy_.get()); + // Once the above function returns it is guaranteed that proxy_ or + // source_callback_ would not be used on the backend thread, so it is safe + // to reset them. proxy_.reset(); source_callback_ = nullptr; } void SetVolume(double volume) override { - DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); + DCHECK_CALLED_ON_VALID_THREAD(audio_thread_checker_); + base::AutoLock auto_lock(volume_lock_); volume_ = volume; } void GetVolume(double* volume) override { - DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); + DCHECK_CALLED_ON_VALID_THREAD(audio_thread_checker_); *volume = volume_; } @@ -140,56 +154,57 @@ // ::media::AudioConverter::InputCallback implementation double ProvideInput(::media::AudioBus* audio_bus, uint32_t frames_delayed) override { + // Called on backend thread. Member variables accessed from both backend + // and audio thread must be thread-safe. DCHECK(source_callback_); const base::TimeDelta delay = ::media::AudioTimestampHelper::FramesToTime( frames_delayed, input_params_.sample_rate()); source_callback_->OnMoreData(delay, base::TimeTicks::Now(), 0, audio_bus); + + base::AutoLock auto_lock(volume_lock_); return volume_; } - CastAudioManager* const audio_manager_; CastAudioMixer* const audio_mixer_; - - std::unique_ptr<ResamplerProxy> proxy_; - AudioSourceCallback* source_callback_; const ::media::AudioParameters input_params_; const ::media::AudioParameters output_params_; + bool opened_; double volume_; + base::Lock volume_lock_; + AudioSourceCallback* source_callback_; + std::unique_ptr<ResamplerProxy> proxy_; + THREAD_CHECKER(audio_thread_checker_); DISALLOW_COPY_AND_ASSIGN(MixerProxyStream); }; -CastAudioMixer::CastAudioMixer(const RealStreamFactory& real_stream_factory) - : error_(false), - real_stream_factory_(real_stream_factory), - output_stream_(nullptr) { +CastAudioMixer::CastAudioMixer(CastAudioManager* audio_manager) + : audio_manager_(audio_manager), error_(false), output_stream_(nullptr) { output_params_ = ::media::AudioParameters( ::media::AudioParameters::Format::AUDIO_PCM_LOW_LATENCY, ::media::CHANNEL_LAYOUT_STEREO, kSampleRate, kBitsPerSample, kFramesPerBuffer); mixer_.reset( new ::media::AudioConverter(output_params_, output_params_, false)); - thread_checker_.DetachFromThread(); + DETACH_FROM_THREAD(audio_thread_checker_); } CastAudioMixer::~CastAudioMixer() {} ::media::AudioOutputStream* CastAudioMixer::MakeStream( - const ::media::AudioParameters& params, - CastAudioManager* audio_manager) { - return new MixerProxyStream(params, output_params_, audio_manager, this); + const ::media::AudioParameters& params) { + DCHECK_CALLED_ON_VALID_THREAD(audio_thread_checker_); + return new MixerProxyStream(params, output_params_, this); } bool CastAudioMixer::Register(MixerProxyStream* proxy_stream) { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(audio_thread_checker_); DCHECK(std::find(proxy_streams_.begin(), proxy_streams_.end(), proxy_stream) == proxy_streams_.end()); - // If the mixer is in an error state, do not allow any new - // registrations until every active stream has been - // unregistered. + // Do not allow opening new streams while in error state. if (error_) return false; @@ -198,7 +213,7 @@ // is not opened properly. if (proxy_streams_.empty()) { DCHECK(!output_stream_); - output_stream_ = real_stream_factory_.Run(output_params_); + output_stream_ = audio_manager_->MakeMixerOutputStream(output_params_); if (!output_stream_->Open()) { output_stream_->Close(); output_stream_ = nullptr; @@ -206,17 +221,16 @@ } } - proxy_streams_.push_back(proxy_stream); + proxy_streams_.insert(proxy_stream); return true; } void CastAudioMixer::Unregister(MixerProxyStream* proxy_stream) { - DCHECK(thread_checker_.CalledOnValidThread()); - auto it = - std::find(proxy_streams_.begin(), proxy_streams_.end(), proxy_stream); - DCHECK(it != proxy_streams_.end()); + DCHECK_CALLED_ON_VALID_THREAD(audio_thread_checker_); + DCHECK(std::find(proxy_streams_.begin(), proxy_streams_.end(), + proxy_stream) != proxy_streams_.end()); - proxy_streams_.erase(it); + proxy_streams_.erase(proxy_stream); // Reset the state once all streams have been unregistered. if (proxy_streams_.empty()) { @@ -230,19 +244,25 @@ void CastAudioMixer::AddInput( ::media::AudioConverter::InputCallback* input_callback) { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(audio_thread_checker_); // Start the backend if there are no current inputs. if (mixer_->empty() && output_stream_) output_stream_->Start(this); + + base::AutoLock auto_lock(mixer_lock_); mixer_->AddInput(input_callback); } void CastAudioMixer::RemoveInput( ::media::AudioConverter::InputCallback* input_callback) { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(audio_thread_checker_); - mixer_->RemoveInput(input_callback); + { + base::AutoLock auto_lock(mixer_lock_); + mixer_->RemoveInput(input_callback); + } + // Stop |output_stream_| if there are no inputs and the stream is running. if (mixer_->empty() && output_stream_) output_stream_->Stop(); @@ -252,36 +272,28 @@ base::TimeTicks /* delay_timestamp */, int /* prior_frames_skipped */, ::media::AudioBus* dest) { - DCHECK(thread_checker_.CalledOnValidThread()); - + // Called on backend thread. uint32_t frames_delayed = ::media::AudioTimestampHelper::TimeToFrames( delay, output_params_.sample_rate()); + + base::AutoLock auto_lock(mixer_lock_); mixer_->ConvertWithDelay(frames_delayed, dest); return dest->frames(); } void CastAudioMixer::OnError() { - DCHECK(thread_checker_.CalledOnValidThread()); + // Called on backend thread. + audio_manager_->GetTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce(&CastAudioMixer::HandleError, base::Unretained(this))); +} - // TODO(ameyak): Add rate limiting. If errors are seen to occur - // above some arbitrary value in a specified amount - // of time, signal errors to all currently active - // streams and close. +void CastAudioMixer::HandleError() { + DCHECK_CALLED_ON_VALID_THREAD(audio_thread_checker_); - output_stream_->Stop(); - output_stream_->Close(); - output_stream_ = real_stream_factory_.Run(output_params_); - - if (output_stream_->Open()) { - output_stream_->Start(this); - } else { - // Assume error state - output_stream_->Close(); - output_stream_ = nullptr; - error_ = true; - for (auto it = proxy_streams_.begin(); it != proxy_streams_.end(); it++) - (*it)->OnError(); - } + error_ = true; + for (auto it = proxy_streams_.begin(); it != proxy_streams_.end(); ++it) + (*it)->OnError(); } } // namespace media
diff --git a/chromecast/media/audio/cast_audio_mixer.h b/chromecast/media/audio/cast_audio_mixer.h index 7927f4259..0a67090 100644 --- a/chromecast/media/audio/cast_audio_mixer.h +++ b/chromecast/media/audio/cast_audio_mixer.h
@@ -6,7 +6,7 @@ #define CHROMECAST_MEDIA_AUDIO_CAST_AUDIO_MIXER_H_ #include <memory> -#include <vector> +#include <set> #include "base/callback.h" #include "base/macros.h" @@ -25,15 +25,11 @@ // stream down to a single AudioOutputStream to be rendered by the CMA backend. class CastAudioMixer : public ::media::AudioOutputStream::AudioSourceCallback { public: - using RealStreamFactory = base::Callback<::media::AudioOutputStream*( - const ::media::AudioParameters&)>; - - explicit CastAudioMixer(const RealStreamFactory& real_stream_factory); + explicit CastAudioMixer(CastAudioManager* audio_manager); ~CastAudioMixer() override; virtual ::media::AudioOutputStream* MakeStream( - const ::media::AudioParameters& params, - CastAudioManager* audio_manager); + const ::media::AudioParameters& params); private: class MixerProxyStream; @@ -43,7 +39,6 @@ base::TimeTicks delay_timestamp, int prior_frames_skipped, ::media::AudioBus* dest) override; - void OnError() override; // MixedAudioOutputStreams call Register on opening and AddInput on starting. @@ -51,17 +46,17 @@ void Unregister(MixerProxyStream* proxy_stream); void AddInput(::media::AudioConverter::InputCallback* input_callback); void RemoveInput(::media::AudioConverter::InputCallback* input_callback); + void HandleError(); - base::ThreadChecker thread_checker_; - std::unique_ptr<::media::AudioConverter> mixer_; + CastAudioManager* const audio_manager_; bool error_; - - const RealStreamFactory real_stream_factory_; - ::media::AudioOutputStream* output_stream_; + std::set<MixerProxyStream*> proxy_streams_; + std::unique_ptr<::media::AudioConverter> mixer_; + base::Lock mixer_lock_; ::media::AudioParameters output_params_; + ::media::AudioOutputStream* output_stream_; - std::vector<MixerProxyStream*> proxy_streams_; - + THREAD_CHECKER(audio_thread_checker_); DISALLOW_COPY_AND_ASSIGN(CastAudioMixer); };
diff --git a/chromecast/media/audio/cast_audio_mixer_unittest.cc b/chromecast/media/audio/cast_audio_mixer_unittest.cc index 9477967..131c087 100644 --- a/chromecast/media/audio/cast_audio_mixer_unittest.cc +++ b/chromecast/media/audio/cast_audio_mixer_unittest.cc
@@ -17,6 +17,7 @@ #include "base/time/time.h" #include "chromecast/media/audio/cast_audio_manager.h" #include "chromecast/media/audio/cast_audio_output_stream.h" +#include "chromecast/media/cma/test/mock_media_pipeline_backend_factory.h" #include "media/audio/test_audio_thread.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -25,10 +26,12 @@ namespace media { namespace { -using ::testing::_; -using ::testing::Invoke; -using ::testing::Return; -using ::testing::StrictMock; +using testing::_; +using testing::Assign; +using testing::Invoke; +using testing::Return; +using testing::SaveArg; +using testing::StrictMock; // Utility functions ::media::AudioParameters GetAudioParams() { @@ -87,11 +90,12 @@ class MockCastAudioManager : public CastAudioManager { public: - MockCastAudioManager(CastAudioMixer* audio_mixer) + MockCastAudioManager() : CastAudioManager(base::MakeUnique<::media::TestAudioThread>(), nullptr, nullptr, - audio_mixer) { + nullptr, + true /* use_mixer */) { ON_CALL(*this, ReleaseOutputStream(_)) .WillByDefault( Invoke(this, &MockCastAudioManager::ReleaseOutputStreamConcrete)); @@ -108,69 +112,42 @@ } }; -class MockCastAudioMixer : public CastAudioMixer { - public: - explicit MockCastAudioMixer(const RealStreamFactory& real_stream_factory) - : CastAudioMixer(real_stream_factory) { - ON_CALL(*this, MakeStream(_, _)) - .WillByDefault(Invoke(this, &MockCastAudioMixer::MakeStreamConcrete)); - } - - MOCK_METHOD2( - MakeStream, - ::media::AudioOutputStream*(const ::media::AudioParameters& params, - CastAudioManager* audio_manager)); - - private: - ::media::AudioOutputStream* MakeStreamConcrete( - const ::media::AudioParameters& params, - CastAudioManager* audio_manager) { - return CastAudioMixer::MakeStream(params, audio_manager); - } -}; - // Generates StrictMocks of Mixer, Manager, and Mixer OutputStream. class CastAudioMixerTest : public ::testing::Test { public: - CastAudioMixerTest() {} + CastAudioMixerTest() : source_callback_(nullptr) {} ~CastAudioMixerTest() override {} protected: void SetUp() override { - // |this| will outlive |mock_mixer_| - mock_mixer_ = new StrictMock<MockCastAudioMixer>( - base::Bind(&CastAudioMixerTest::MakeMixerOutputStreamProxy, - base::Unretained(this))); - mock_manager_.reset(new StrictMock<MockCastAudioManager>(mock_mixer_)); + mock_manager_.reset(new StrictMock<MockCastAudioManager>()); mock_mixer_stream_.reset(new StrictMock<MockCastAudioOutputStream>( GetAudioParams(), mock_manager_.get())); + + ON_CALL(*mock_manager_, MakeMixerOutputStream(_)) + .WillByDefault(Return(mock_mixer_stream_.get())); + ON_CALL(*mock_mixer_stream_, Start(_)) + .WillByDefault(SaveArg<0>(&source_callback_)); + ON_CALL(*mock_mixer_stream_, Stop()) + .WillByDefault(Assign(&source_callback_, nullptr)); } void TearDown() override { mock_manager_->Shutdown(); } MockCastAudioManager& mock_manager() { return *mock_manager_; } - - MockCastAudioMixer& mock_mixer() { return *mock_mixer_; } - MockCastAudioOutputStream& mock_mixer_stream() { return *mock_mixer_stream_; } ::media::AudioOutputStream* CreateMixerStream() { - EXPECT_CALL(*mock_mixer_, MakeStream(_, &mock_manager())); return mock_manager_->MakeAudioOutputStream( GetAudioParams(), "", ::media::AudioManager::LogCallback()); } - private: - ::media::AudioOutputStream* MakeMixerOutputStreamProxy( - const ::media::AudioParameters& audio_params) { - return mock_manager_ ? mock_manager_->MakeMixerOutputStream(audio_params) - : nullptr; - } - base::MessageLoop message_loop_; - MockCastAudioMixer* mock_mixer_; std::unique_ptr<MockCastAudioManager> mock_manager_; std::unique_ptr<MockCastAudioOutputStream> mock_mixer_stream_; + + // Saved params passed to |mock_mixer_stream_|. + ::media::AudioOutputStream::AudioSourceCallback* source_callback_; }; TEST_F(CastAudioMixerTest, Volume) { @@ -234,7 +211,7 @@ EXPECT_CALL(mock_mixer_stream(), Open()).WillOnce(Return(true)); ASSERT_TRUE(stream->Open()); - EXPECT_CALL(mock_mixer_stream(), Start(&mock_mixer())); + EXPECT_CALL(mock_mixer_stream(), Start(_)); stream->Start(&source); stream->Start(&source); @@ -254,7 +231,7 @@ EXPECT_CALL(mock_mixer_stream(), Open()).WillOnce(Return(true)); ASSERT_TRUE(stream->Open()); - EXPECT_CALL(mock_mixer_stream(), Start(&mock_mixer())).Times(2); + EXPECT_CALL(mock_mixer_stream(), Start(_)).Times(2); EXPECT_CALL(mock_mixer_stream(), Stop()).Times(2); stream->Start(&source); stream->Stop(); @@ -283,7 +260,7 @@ for (auto* stream : streams) ASSERT_TRUE(stream->Open()); - EXPECT_CALL(mock_mixer_stream(), Start(&mock_mixer())); + EXPECT_CALL(mock_mixer_stream(), Start(_)); for (unsigned int i = 0; i < streams.size(); i++) streams[i]->Start(sources[i].get()); @@ -296,7 +273,7 @@ for (auto& source : sources) EXPECT_CALL(*source, OnMoreData(_, _, _, _)); - mock_mixer_stream().SignalPull(&mock_mixer(), base::TimeDelta()); + mock_mixer_stream().SignalPull(source_callback_, base::TimeDelta()); EXPECT_CALL(mock_manager(), ReleaseOutputStream(stream)); stream->Close(); @@ -324,7 +301,7 @@ ASSERT_TRUE(stream1->Open()); ASSERT_TRUE(stream2->Open()); - EXPECT_CALL(mock_mixer_stream(), Start(&mock_mixer())); + EXPECT_CALL(mock_mixer_stream(), Start(_)); stream1->Start(&source); stream2->Start(&source); @@ -338,7 +315,7 @@ } } -TEST_F(CastAudioMixerTest, OnErrorRecovery) { +TEST_F(CastAudioMixerTest, OnError) { MockAudioSourceCallback source; std::vector<::media::AudioOutputStream*> streams; @@ -353,79 +330,36 @@ for (auto* stream : streams) ASSERT_TRUE(stream->Open()); - EXPECT_CALL(mock_mixer_stream(), Start(&mock_mixer())); + EXPECT_CALL(mock_mixer_stream(), Start(_)); streams.front()->Start(&source); - EXPECT_CALL(mock_mixer_stream(), Stop()); - EXPECT_CALL(mock_mixer_stream(), Close()); - EXPECT_CALL(mock_manager(), MakeMixerOutputStream(_)) - .WillOnce(Return(&mock_mixer_stream())); - EXPECT_CALL(mock_mixer_stream(), Open()).WillOnce(Return(true)); - EXPECT_CALL(mock_mixer_stream(), Start(&mock_mixer())); - - // The MockAudioSourceCallback should not receive any call OnError. - mock_mixer_stream().SignalError(&mock_mixer()); - - // Try to add another stream. - streams.push_back(CreateMixerStream()); - ASSERT_TRUE(streams.back()); - ASSERT_TRUE(streams.back()->Open()); - - EXPECT_CALL(mock_mixer_stream(), Stop()); - EXPECT_CALL(mock_mixer_stream(), Close()); - for (auto* stream : streams) { - EXPECT_CALL(mock_manager(), ReleaseOutputStream(stream)); - stream->Close(); - } -} - -TEST_F(CastAudioMixerTest, OnErrorNoRecovery) { - MockAudioSourceCallback source; - std::vector<::media::AudioOutputStream*> streams; - - streams.push_back(CreateMixerStream()); - streams.push_back(CreateMixerStream()); - for (auto* stream : streams) - ASSERT_TRUE(stream); - - EXPECT_CALL(mock_manager(), MakeMixerOutputStream(_)) - .WillOnce(Return(&mock_mixer_stream())); - EXPECT_CALL(mock_mixer_stream(), Open()).WillOnce(Return(true)); - for (auto* stream : streams) - ASSERT_TRUE(stream->Open()); - - EXPECT_CALL(mock_mixer_stream(), Start(&mock_mixer())); - streams.front()->Start(&source); - - EXPECT_CALL(mock_mixer_stream(), Stop()); - EXPECT_CALL(mock_manager(), MakeMixerOutputStream(_)) - .WillOnce(Return(&mock_mixer_stream())); - EXPECT_CALL(mock_mixer_stream(), Open()).WillOnce(Return(false)); - EXPECT_CALL(mock_mixer_stream(), Close()).Times(2); + // Note that error will only be triggered on the first stream because that + // is the only stream that has been started. EXPECT_CALL(source, OnError()); - - // The MockAudioSourceCallback should receive an OnError call. - mock_mixer_stream().SignalError(&mock_mixer()); + mock_mixer_stream().SignalError(source_callback_); + base::RunLoop().RunUntilIdle(); // Try to add another stream. streams.push_back(CreateMixerStream()); ASSERT_TRUE(streams.back()); ASSERT_FALSE(streams.back()->Open()); + EXPECT_CALL(mock_mixer_stream(), Stop()); + EXPECT_CALL(mock_mixer_stream(), Close()); for (auto* stream : streams) { EXPECT_CALL(mock_manager(), ReleaseOutputStream(stream)); stream->Close(); } + streams.clear(); // Now that the state has been refreshed, attempt to open a stream. - streams.clear(); streams.push_back(CreateMixerStream()); EXPECT_CALL(mock_manager(), MakeMixerOutputStream(_)) .WillOnce(Return(&mock_mixer_stream())); EXPECT_CALL(mock_mixer_stream(), Open()).WillOnce(Return(true)); ASSERT_TRUE(streams.front()->Open()); - EXPECT_CALL(mock_mixer_stream(), Start(&mock_mixer())); + EXPECT_CALL(mock_mixer_stream(), Start(_)); streams.front()->Start(&source); EXPECT_CALL(mock_mixer_stream(), Stop()); @@ -443,14 +377,14 @@ EXPECT_CALL(mock_mixer_stream(), Open()).WillOnce(Return(true)); ASSERT_TRUE(stream->Open()); - EXPECT_CALL(mock_mixer_stream(), Start(&mock_mixer())); + EXPECT_CALL(mock_mixer_stream(), Start(_)); stream->Start(&source); // |delay| is the same because the Mixer and stream are // using the same AudioParameters. base::TimeDelta delay = base::TimeDelta::FromMicroseconds(1000); EXPECT_CALL(source, OnMoreData(delay, _, 0, _)); - mock_mixer_stream().SignalPull(&mock_mixer(), delay); + mock_mixer_stream().SignalPull(source_callback_, delay); EXPECT_CALL(mock_mixer_stream(), Stop()); EXPECT_CALL(mock_mixer_stream(), Close());
diff --git a/chromecast/media/audio/cast_audio_output_stream.cc b/chromecast/media/audio/cast_audio_output_stream.cc index 0735211..d0d7419 100644 --- a/chromecast/media/audio/cast_audio_output_stream.cc +++ b/chromecast/media/audio/cast_audio_output_stream.cc
@@ -9,19 +9,30 @@ #include "base/bind.h" #include "base/callback_helpers.h" +#include "base/synchronization/waitable_event.h" +#include "base/threading/thread_task_runner_handle.h" #include "chromecast/base/metrics/cast_metrics_helper.h" #include "chromecast/base/task_runner_impl.h" #include "chromecast/media/audio/cast_audio_manager.h" +#include "chromecast/media/cma/backend/media_pipeline_backend_factory.h" #include "chromecast/media/cma/base/decoder_buffer_adapter.h" #include "chromecast/public/media/decoder_config.h" #include "chromecast/public/media/media_pipeline_backend.h" #include "chromecast/public/media/media_pipeline_device_params.h" #include "chromecast/public/volume_control.h" #include "media/audio/audio_device_description.h" +#include "media/base/audio_timestamp_helper.h" #include "media/base/decoder_buffer.h" namespace { const int kMaxQueuedDataMs = 1000; + +void SignalWaitableEvent(bool* success, + base::WaitableEvent* waitable_event, + bool result) { + *success = result; + waitable_event->Signal(); +} } // namespace namespace chromecast { @@ -33,17 +44,29 @@ class CastAudioOutputStream::Backend : public MediaPipelineBackend::Decoder::Delegate { public: - using PushBufferCompletionCallback = base::Callback<void(bool)>; + using OpenCompletionCallback = base::OnceCallback<void(bool)>; - Backend() : decoder_(nullptr), first_start_(true), error_(false) { - thread_checker_.DetachFromThread(); + Backend(const ::media::AudioParameters& audio_params) + : audio_params_(audio_params), + timestamp_helper_(audio_params_.sample_rate()), + buffer_duration_(audio_params.GetBufferDuration()), + first_start_(true), + push_in_progress_(false), + decoder_(nullptr), + source_callback_(nullptr), + weak_factory_(this) { + DETACH_FROM_THREAD(thread_checker_); } - ~Backend() override {} + ~Backend() override { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (backend_ && !first_start_) // Only stop the backend if it was started. + backend_->Stop(); + } - bool Open(const ::media::AudioParameters& audio_params, - CastAudioManager* audio_manager) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(audio_manager); + void Open(MediaPipelineBackendFactory* backend_factory, + OpenCompletionCallback completion_cb) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(backend_factory); DCHECK(backend_ == nullptr); backend_task_runner_.reset(new TaskRunnerImpl()); @@ -52,38 +75,44 @@ MediaPipelineDeviceParams::kAudioStreamSoundEffects, backend_task_runner_.get(), AudioContentType::kMedia, ::media::AudioDeviceDescription::kDefaultDeviceId); - backend_ = audio_manager->CreateMediaPipelineBackend(device_params); - if (!backend_) - return false; + backend_ = backend_factory->CreateBackend(device_params); + if (!backend_) { + std::move(completion_cb).Run(false); + return; + } decoder_ = backend_->CreateAudioDecoder(); - if (!decoder_) - return false; + if (!decoder_) { + std::move(completion_cb).Run(false); + return; + } decoder_->SetDelegate(this); AudioConfig audio_config; audio_config.codec = kCodecPCM; audio_config.sample_format = kSampleFormatS16; - audio_config.bytes_per_channel = audio_params.bits_per_sample() / 8; - audio_config.channel_number = audio_params.channels(); - audio_config.samples_per_second = audio_params.sample_rate(); - if (!decoder_->SetConfig(audio_config)) - return false; + audio_config.bytes_per_channel = audio_params_.bits_per_sample() / 8; + audio_config.channel_number = audio_params_.channels(); + audio_config.samples_per_second = audio_params_.sample_rate(); + if (!decoder_->SetConfig(audio_config)) { + std::move(completion_cb).Run(false); + return; + } - return backend_->Initialize(); + if (!backend_->Initialize()) { + std::move(completion_cb).Run(false); + return; + } + + audio_bus_ = ::media::AudioBus::Create(audio_params_); + decoder_buffer_ = new DecoderBufferAdapter( + new ::media::DecoderBuffer(audio_params_.GetBytesPerBuffer())); + timestamp_helper_.SetBaseTimestamp(base::TimeDelta()); + std::move(completion_cb).Run(true); } - void Close() { - DCHECK(thread_checker_.CalledOnValidThread()); - - if (backend_ && !first_start_) // Only stop the backend if it was started. - backend_->Stop(); - backend_.reset(); - backend_task_runner_.reset(); - } - - void Start() { - DCHECK(thread_checker_.CalledOnValidThread()); + void Start(AudioSourceCallback* source_callback) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(backend_); if (first_start_) { @@ -92,66 +121,100 @@ } else { backend_->Resume(); } + + source_callback_ = source_callback; + next_push_time_ = base::TimeTicks::Now(); + if (!push_in_progress_) { + push_in_progress_ = true; + PushBuffer(); + } } - void Stop() { - DCHECK(thread_checker_.CalledOnValidThread()); + void Stop(base::OnceClosure completion_cb) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(backend_); backend_->Pause(); - } - - void PushBuffer(scoped_refptr<media::DecoderBufferBase> decoder_buffer, - const PushBufferCompletionCallback& completion_cb) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(decoder_); - DCHECK(!completion_cb.is_null()); - DCHECK(completion_cb_.is_null()); - if (error_) { - completion_cb.Run(false); - return; - } - - backend_buffer_ = decoder_buffer; - completion_cb_ = completion_cb; - BufferStatus status = decoder_->PushBuffer(backend_buffer_.get()); - if (status != MediaPipelineBackend::kBufferPending) - OnPushBufferComplete(status); + source_callback_ = nullptr; + std::move(completion_cb).Run(); } void SetVolume(double volume) { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(decoder_); decoder_->SetVolume(volume); } - MediaPipelineBackend::AudioDecoder::RenderingDelay GetRenderingDelay() { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(decoder_); - return decoder_->GetRenderingDelay(); + private: + void PushBuffer() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(push_in_progress_); + + if (!source_callback_) { + push_in_progress_ = false; + return; + } + + MediaPipelineBackend::AudioDecoder::RenderingDelay rendering_delay = + decoder_->GetRenderingDelay(); + base::TimeDelta delay = + base::TimeDelta::FromMicroseconds(rendering_delay.delay_microseconds); + base::TimeTicks delay_timestamp = + base::TimeTicks() + base::TimeDelta::FromMicroseconds( + rendering_delay.timestamp_microseconds); + int frame_count = source_callback_->OnMoreData(delay, delay_timestamp, 0, + audio_bus_.get()); + VLOG(3) << "frames_filled=" << frame_count << " with latency=" << delay; + + DCHECK_EQ(frame_count, audio_bus_->frames()); + DCHECK_EQ(static_cast<int>(decoder_buffer_->data_size()), + frame_count * audio_params_.GetBytesPerFrame()); + audio_bus_->ToInterleaved(frame_count, audio_params_.bits_per_sample() / 8, + decoder_buffer_->writable_data()); + decoder_buffer_->set_timestamp(timestamp_helper_.GetTimestamp()); + timestamp_helper_.AddFrames(frame_count); + + BufferStatus status = decoder_->PushBuffer(decoder_buffer_.get()); + if (status != MediaPipelineBackend::kBufferPending) + OnPushBufferComplete(status); } - private: // MediaPipelineBackend::Decoder::Delegate implementation void OnPushBufferComplete(BufferStatus status) override { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_NE(status, MediaPipelineBackend::kBufferPending); - // |completion_cb_| may be null if OnDecoderError was called. - if (completion_cb_.is_null()) + DCHECK(push_in_progress_); + push_in_progress_ = false; + + if (!source_callback_) return; - base::ResetAndReturn(&completion_cb_) - .Run(status == MediaPipelineBackend::kBufferSuccess); + if (status != MediaPipelineBackend::kBufferSuccess) { + source_callback_->OnError(); + return; + } + + // Schedule next push buffer. We don't want to allow more than + // kMaxQueuedDataMs of queued audio. + const base::TimeTicks now = base::TimeTicks::Now(); + next_push_time_ = std::max(now, next_push_time_ + buffer_duration_); + + base::TimeDelta delay = (next_push_time_ - now) - + base::TimeDelta::FromMilliseconds(kMaxQueuedDataMs); + delay = std::max(delay, base::TimeDelta()); + + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, base::Bind(&Backend::PushBuffer, weak_factory_.GetWeakPtr()), + delay); + push_in_progress_ = true; } void OnEndOfStream() override {} void OnDecoderError() override { - DCHECK(thread_checker_.CalledOnValidThread()); - error_ = true; - if (!completion_cb_.is_null()) - OnPushBufferComplete(MediaPipelineBackend::kBufferFailed); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + OnPushBufferComplete(MediaPipelineBackend::kBufferFailed); } void OnKeyStatusChanged(const std::string& key_id, @@ -160,15 +223,21 @@ void OnVideoResolutionChanged(const Size& size) override {} - std::unique_ptr<MediaPipelineBackend> backend_; - std::unique_ptr<TaskRunnerImpl> backend_task_runner_; - MediaPipelineBackend::AudioDecoder* decoder_; - PushBufferCompletionCallback completion_cb_; + const ::media::AudioParameters audio_params_; + std::unique_ptr<::media::AudioBus> audio_bus_; + scoped_refptr<media::DecoderBufferBase> decoder_buffer_; + ::media::AudioTimestampHelper timestamp_helper_; + const base::TimeDelta buffer_duration_; bool first_start_; - bool error_; - scoped_refptr<DecoderBufferBase> backend_buffer_; - base::ThreadChecker thread_checker_; + bool push_in_progress_; + base::TimeTicks next_push_time_; + std::unique_ptr<TaskRunnerImpl> backend_task_runner_; + std::unique_ptr<MediaPipelineBackend> backend_; + MediaPipelineBackend::AudioDecoder* decoder_; + AudioSourceCallback* source_callback_; + THREAD_CHECKER(thread_checker_); + base::WeakPtrFactory<Backend> weak_factory_; DISALLOW_COPY_AND_ASSIGN(Backend); }; @@ -176,23 +245,17 @@ CastAudioOutputStream::CastAudioOutputStream( const ::media::AudioParameters& audio_params, CastAudioManager* audio_manager) - : audio_params_(audio_params), - audio_manager_(audio_manager), - volume_(1.0), - source_callback_(nullptr), - timestamp_helper_(audio_params_.sample_rate()), - backend_(new Backend()), - buffer_duration_(audio_params.GetBufferDuration()), - push_in_progress_(false), - weak_factory_(this) { + : audio_params_(audio_params), audio_manager_(audio_manager), volume_(1.0) { VLOG(1) << "CastAudioOutputStream " << this << " created with " << audio_params_.AsHumanReadableString(); } CastAudioOutputStream::~CastAudioOutputStream() { + DCHECK(!backend_); } bool CastAudioOutputStream::Open() { + VLOG(1) << this << ": " << __func__; DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); ::media::AudioParameters::Format format = audio_params_.format(); @@ -208,60 +271,80 @@ DCHECK_GE(audio_params_.channels(), 1); DCHECK_LE(audio_params_.channels(), 2); - if (!backend_->Open(audio_params_, audio_manager_)) { - LOG(WARNING) << "Failed to create media pipeline backend."; - return false; + bool success = false; + DCHECK(!backend_); + backend_ = base::MakeUnique<Backend>(audio_params_); + { + base::WaitableEvent completion_event( + base::WaitableEvent::ResetPolicy::AUTOMATIC, + base::WaitableEvent::InitialState::NOT_SIGNALED); + audio_manager_->backend_task_runner()->PostTask( + FROM_HERE, + base::BindOnce( + &Backend::Open, base::Unretained(backend_.get()), + audio_manager_->backend_factory(), + base::BindOnce(&SignalWaitableEvent, &success, &completion_event))); + completion_event.Wait(); } - audio_bus_ = ::media::AudioBus::Create(audio_params_); - decoder_buffer_ = new DecoderBufferAdapter( - new ::media::DecoderBuffer(audio_params_.GetBytesPerBuffer())); - timestamp_helper_.SetBaseTimestamp(base::TimeDelta()); - - VLOG(1) << __FUNCTION__ << " : " << this; - return true; + if (!success) + LOG(WARNING) << "Failed to open audio output stream."; + return success; } void CastAudioOutputStream::Close() { + VLOG(1) << this << ": " << __func__; DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); - VLOG(1) << __FUNCTION__ << " : " << this; - backend_->Close(); + DCHECK(backend_); + audio_manager_->backend_task_runner()->DeleteSoon(FROM_HERE, + backend_.release()); + // Signal to the manager that we're closed and can be removed. // This should be the last call in the function as it deletes "this". audio_manager_->ReleaseOutputStream(this); } void CastAudioOutputStream::Start(AudioSourceCallback* source_callback) { + VLOG(2) << this << ": " << __func__; DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); DCHECK(source_callback); + DCHECK(backend_); - source_callback_ = source_callback; - backend_->Start(); - - next_push_time_ = base::TimeTicks::Now(); - if (!push_in_progress_) { - audio_manager_->GetTaskRunner()->PostTask( - FROM_HERE, base::Bind(&CastAudioOutputStream::PushBuffer, - weak_factory_.GetWeakPtr())); - push_in_progress_ = true; - } + audio_manager_->backend_task_runner()->PostTask( + FROM_HERE, + base::BindOnce(&Backend::Start, base::Unretained(backend_.get()), + source_callback)); metrics::CastMetricsHelper::GetInstance()->LogTimeToFirstAudio(); } void CastAudioOutputStream::Stop() { + VLOG(2) << this << ": " << __func__; DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); + DCHECK(backend_); - source_callback_ = nullptr; - backend_->Stop(); + base::WaitableEvent completion_event( + base::WaitableEvent::ResetPolicy::AUTOMATIC, + base::WaitableEvent::InitialState::NOT_SIGNALED); + audio_manager_->backend_task_runner()->PostTask( + FROM_HERE, + base::BindOnce(&Backend::Stop, base::Unretained(backend_.get()), + base::BindOnce(&base::WaitableEvent::Signal, + base::Unretained(&completion_event)))); + completion_event.Wait(); } void CastAudioOutputStream::SetVolume(double volume) { + VLOG(2) << this << ": " << __func__ << "(" << volume << ")"; DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); volume_ = volume; - backend_->SetVolume(volume); + if (backend_) { + audio_manager_->backend_task_runner()->PostTask( + FROM_HERE, base::BindOnce(&Backend::SetVolume, + base::Unretained(backend_.get()), volume_)); + } } void CastAudioOutputStream::GetVolume(double* volume) { @@ -270,67 +353,5 @@ *volume = volume_; } -void CastAudioOutputStream::PushBuffer() { - DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); - DCHECK(push_in_progress_); - - if (!source_callback_) { - push_in_progress_ = false; - return; - } - - MediaPipelineBackend::AudioDecoder::RenderingDelay rendering_delay = - backend_->GetRenderingDelay(); - base::TimeDelta delay = - base::TimeDelta::FromMicroseconds(rendering_delay.delay_microseconds); - base::TimeTicks delay_timestamp = - base::TimeTicks() + - base::TimeDelta::FromMicroseconds(rendering_delay.timestamp_microseconds); - int frame_count = - source_callback_->OnMoreData(delay, delay_timestamp, 0, audio_bus_.get()); - VLOG(3) << "frames_filled=" << frame_count << " with latency=" << delay; - - DCHECK_EQ(frame_count, audio_bus_->frames()); - DCHECK_EQ(static_cast<int>(decoder_buffer_->data_size()), - frame_count * audio_params_.GetBytesPerFrame()); - audio_bus_->ToInterleaved(frame_count, audio_params_.bits_per_sample() / 8, - decoder_buffer_->writable_data()); - decoder_buffer_->set_timestamp(timestamp_helper_.GetTimestamp()); - timestamp_helper_.AddFrames(frame_count); - - auto completion_cb = base::Bind(&CastAudioOutputStream::OnPushBufferComplete, - weak_factory_.GetWeakPtr()); - backend_->PushBuffer(decoder_buffer_, completion_cb); -} - -void CastAudioOutputStream::OnPushBufferComplete(bool success) { - DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); - DCHECK(push_in_progress_); - - push_in_progress_ = false; - - if (!source_callback_) - return; - if (!success) { - source_callback_->OnError(); - return; - } - - // Schedule next push buffer. We don't want to allow more than - // kMaxQueuedDataMs of queued audio. - const base::TimeTicks now = base::TimeTicks::Now(); - next_push_time_ = std::max(now, next_push_time_ + buffer_duration_); - - base::TimeDelta delay = (next_push_time_ - now) - - base::TimeDelta::FromMilliseconds(kMaxQueuedDataMs); - delay = std::max(delay, base::TimeDelta()); - - audio_manager_->GetTaskRunner()->PostDelayedTask( - FROM_HERE, base::Bind(&CastAudioOutputStream::PushBuffer, - weak_factory_.GetWeakPtr()), - delay); - push_in_progress_ = true; -} - } // namespace media } // namespace chromecast
diff --git a/chromecast/media/audio/cast_audio_output_stream.h b/chromecast/media/audio/cast_audio_output_stream.h index 7d48e90..4a1d98d 100644 --- a/chromecast/media/audio/cast_audio_output_stream.h +++ b/chromecast/media/audio/cast_audio_output_stream.h
@@ -8,17 +8,13 @@ #include <memory> #include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/time/time.h" #include "media/audio/audio_io.h" #include "media/base/audio_parameters.h" -#include "media/base/audio_timestamp_helper.h" namespace chromecast { namespace media { class CastAudioManager; -class DecoderBufferBase; class CastAudioOutputStream : public ::media::AudioOutputStream { public: @@ -37,23 +33,12 @@ private: class Backend; - void PushBuffer(); - void OnPushBufferComplete(bool success); - const ::media::AudioParameters audio_params_; CastAudioManager* const audio_manager_; - double volume_; - AudioSourceCallback* source_callback_; - std::unique_ptr<::media::AudioBus> audio_bus_; - scoped_refptr<media::DecoderBufferBase> decoder_buffer_; - ::media::AudioTimestampHelper timestamp_helper_; - std::unique_ptr<Backend> backend_; - const base::TimeDelta buffer_duration_; - bool push_in_progress_; - base::TimeTicks next_push_time_; - base::WeakPtrFactory<CastAudioOutputStream> weak_factory_; + // Only valid when the stream is open. + std::unique_ptr<Backend> backend_; DISALLOW_COPY_AND_ASSIGN(CastAudioOutputStream); };
diff --git a/chromecast/media/audio/cast_audio_output_stream_unittest.cc b/chromecast/media/audio/cast_audio_output_stream_unittest.cc index 89744ec..f055c95 100644 --- a/chromecast/media/audio/cast_audio_output_stream_unittest.cc +++ b/chromecast/media/audio/cast_audio_output_stream_unittest.cc
@@ -15,14 +15,19 @@ #include "base/time/time.h" #include "chromecast/base/metrics/cast_metrics_test_helper.h" #include "chromecast/media/audio/cast_audio_manager.h" +#include "chromecast/media/audio/cast_audio_mixer.h" +#include "chromecast/media/cma/test/mock_media_pipeline_backend_factory.h" #include "chromecast/public/media/cast_decoder_buffer.h" #include "chromecast/public/media/media_pipeline_backend.h" +#include "chromecast/public/task_runner.h" +#include "media/audio/mock_audio_source_callback.h" #include "media/audio/test_audio_thread.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -using ::testing::Invoke; -using ::testing::_; +using testing::_; +using testing::Invoke; +using testing::NiceMock; namespace chromecast { namespace media { @@ -39,6 +44,20 @@ return dest->frames(); } +class NotifyPushBufferCompleteTask : public chromecast::TaskRunner::Task { + public: + NotifyPushBufferCompleteTask( + MediaPipelineBackend::Decoder::Delegate* delegate) + : delegate_(delegate) {} + ~NotifyPushBufferCompleteTask() override = default; + void Run() override { + delegate_->OnPushBufferComplete(MediaPipelineBackend::kBufferSuccess); + } + + private: + MediaPipelineBackend::Decoder::Delegate* const delegate_; +}; + class FakeAudioDecoder : public MediaPipelineBackend::AudioDecoder { public: enum PipelineStatus { @@ -48,8 +67,9 @@ PIPELINE_STATUS_ASYNC_ERROR, }; - FakeAudioDecoder() - : volume_(1.0f), + FakeAudioDecoder(const MediaPipelineDeviceParams& params) + : params_(params), + volume_(1.0f), pipeline_status_(PIPELINE_STATUS_OK), pending_push_(false), pushed_buffer_count_(0), @@ -99,7 +119,8 @@ void set_pipeline_status(PipelineStatus status) { if (status == PIPELINE_STATUS_OK && pending_push_) { pending_push_ = false; - delegate_->OnPushBufferComplete(MediaPipelineBackend::kBufferSuccess); + params_.task_runner->PostTask(new NotifyPushBufferCompleteTask(delegate_), + 0); } pipeline_status_ = status; } @@ -110,6 +131,7 @@ CastDecoderBuffer* last_buffer() { return last_buffer_; } private: + const MediaPipelineDeviceParams params_; AudioConfig config_; float volume_; @@ -125,13 +147,14 @@ public: enum State { kStateStopped, kStateRunning, kStatePaused }; - FakeMediaPipelineBackend() : state_(kStateStopped), audio_decoder_(nullptr) {} + FakeMediaPipelineBackend(const MediaPipelineDeviceParams& params) + : params_(params), state_(kStateStopped), audio_decoder_(nullptr) {} ~FakeMediaPipelineBackend() override {} // MediaPipelineBackend implementation: AudioDecoder* CreateAudioDecoder() override { DCHECK(!audio_decoder_); - audio_decoder_ = base::MakeUnique<FakeAudioDecoder>(); + audio_decoder_ = base::MakeUnique<FakeAudioDecoder>(params_); return audio_decoder_.get(); } VideoDecoder* CreateVideoDecoder() override { @@ -166,62 +189,17 @@ FakeAudioDecoder* decoder() const { return audio_decoder_.get(); } private: + const MediaPipelineDeviceParams params_; State state_; std::unique_ptr<FakeAudioDecoder> audio_decoder_; }; -class MockAudioSourceCallback - : public ::media::AudioOutputStream::AudioSourceCallback { - public: - // ::media::AudioOutputStream::AudioSourceCallback overrides. - MOCK_METHOD4(OnMoreData, - int(base::TimeDelta, base::TimeTicks, int, ::media::AudioBus*)); - MOCK_METHOD0(OnError, void()); -}; - -class FakeAudioManager : public CastAudioManager { - public: - FakeAudioManager() - : CastAudioManager(base::MakeUnique<::media::TestAudioThread>(), - nullptr, - nullptr, - nullptr), - media_pipeline_backend_(nullptr) {} - ~FakeAudioManager() override {} - - // CastAudioManager overrides. - std::unique_ptr<MediaPipelineBackend> CreateMediaPipelineBackend( - const MediaPipelineDeviceParams& params) override { - DCHECK(GetTaskRunner()->BelongsToCurrentThread()); - DCHECK(!media_pipeline_backend_); - - std::unique_ptr<FakeMediaPipelineBackend> backend( - new FakeMediaPipelineBackend()); - // Cache the backend locally to be used by tests. - media_pipeline_backend_ = backend.get(); - return std::move(backend); - } - void ReleaseOutputStream(::media::AudioOutputStream* stream) override { - DCHECK(media_pipeline_backend_); - media_pipeline_backend_ = nullptr; - CastAudioManager::ReleaseOutputStream(stream); - } - - // Returns the MediaPipelineBackend being used by the AudioOutputStream. - // Note: here is a valid MediaPipelineBackend only while the stream is open. - // Returns NULL at all other times. - FakeMediaPipelineBackend* media_pipeline_backend() { - return media_pipeline_backend_; - } - - private: - FakeMediaPipelineBackend* media_pipeline_backend_; -}; - class CastAudioOutputStreamTest : public ::testing::Test { public: CastAudioOutputStreamTest() - : format_(::media::AudioParameters::AUDIO_PCM_LINEAR), + : media_thread_("CastMediaThread"), + media_pipeline_backend_(nullptr), + format_(::media::AudioParameters::AUDIO_PCM_LINEAR), channel_layout_(::media::CHANNEL_LAYOUT_MONO), sample_rate_(::media::AudioParameters::kAudioCDSampleRate), bits_per_sample_(16), @@ -231,7 +209,18 @@ protected: void SetUp() override { metrics::InitializeMetricsHelperForTesting(); - audio_manager_ = base::MakeUnique<FakeAudioManager>(); + + CHECK(media_thread_.Start()); + auto backend_factory = + base::MakeUnique<NiceMock<MockMediaPipelineBackendFactory>>(); + ON_CALL(*backend_factory, CreateBackend(_)) + .WillByDefault(Invoke([this](const MediaPipelineDeviceParams& params) { + media_pipeline_backend_ = new FakeMediaPipelineBackend(params); + return base::WrapUnique(media_pipeline_backend_); + })); + audio_manager_ = base::MakeUnique<CastAudioManager>( + base::MakeUnique<::media::TestAudioThread>(), nullptr, + std::move(backend_factory), media_thread_.task_runner(), false); } void TearDown() override { audio_manager_->Shutdown(); } @@ -241,9 +230,7 @@ bits_per_sample_, frames_per_buffer_); } - FakeMediaPipelineBackend* GetBackend() { - return audio_manager_->media_pipeline_backend(); - } + FakeMediaPipelineBackend* GetBackend() { return media_pipeline_backend_; } FakeAudioDecoder* GetAudio() { FakeMediaPipelineBackend* backend = GetBackend(); @@ -269,7 +256,10 @@ } base::MessageLoop message_loop_; - std::unique_ptr<FakeAudioManager> audio_manager_; + base::Thread media_thread_; + std::unique_ptr<CastAudioManager> audio_manager_; + // MockMediaPipelineBackendFactory* backend_factory_; + FakeMediaPipelineBackend* media_pipeline_backend_; // AudioParameters used to create AudioOutputStream. // Tests can modify these parameters before calling CreateStream. ::media::AudioParameters::Format format_; @@ -281,7 +271,7 @@ TEST_F(CastAudioOutputStreamTest, Format) { ::media::AudioParameters::Format format[] = { - //::media::AudioParameters::AUDIO_PCM_LINEAR, + ::media::AudioParameters::AUDIO_PCM_LINEAR, ::media::AudioParameters::AUDIO_PCM_LOW_LATENCY}; for (size_t i = 0; i < arraysize(format); ++i) { format_ = format[i]; @@ -350,7 +340,6 @@ TEST_F(CastAudioOutputStreamTest, DeviceState) { ::media::AudioOutputStream* stream = CreateStream(); ASSERT_TRUE(stream); - EXPECT_FALSE(GetAudio()); EXPECT_TRUE(stream->Open()); FakeAudioDecoder* audio_decoder = GetAudio(); @@ -359,17 +348,18 @@ ASSERT_TRUE(backend); EXPECT_EQ(FakeMediaPipelineBackend::kStateStopped, backend->state()); - auto source_callback(base::MakeUnique<MockAudioSourceCallback>()); - ON_CALL(*source_callback, OnMoreData(_, _, _, _)) - .WillByDefault(Invoke(OnMoreData)); - stream->Start(source_callback.get()); + ::media::MockAudioSourceCallback source_callback; + EXPECT_CALL(source_callback, OnMoreData(_, _, _, _)) + .WillRepeatedly(Invoke(OnMoreData)); + stream->Start(&source_callback); + media_thread_.FlushForTesting(); EXPECT_EQ(FakeMediaPipelineBackend::kStateRunning, backend->state()); stream->Stop(); + media_thread_.FlushForTesting(); EXPECT_EQ(FakeMediaPipelineBackend::kStatePaused, backend->state()); stream->Close(); - EXPECT_FALSE(GetAudio()); } TEST_F(CastAudioOutputStreamTest, PushFrame) { @@ -383,12 +373,12 @@ EXPECT_EQ(0u, audio_decoder->pushed_buffer_count()); EXPECT_FALSE(audio_decoder->last_buffer()); - auto source_callback(base::MakeUnique<MockAudioSourceCallback>()); - ON_CALL(*source_callback, OnMoreData(_, _, _, _)) - .WillByDefault(Invoke(OnMoreData)); + ::media::MockAudioSourceCallback source_callback; + EXPECT_CALL(source_callback, OnMoreData(_, _, _, _)) + .WillRepeatedly(Invoke(OnMoreData)); // No error must be reported to source callback. - EXPECT_CALL(*source_callback, OnError()).Times(0); - stream->Start(source_callback.get()); + EXPECT_CALL(source_callback, OnError()).Times(0); + stream->Start(&source_callback); RunMessageLoopFor(2); stream->Stop(); @@ -418,12 +408,12 @@ ASSERT_TRUE(audio_decoder); audio_decoder->set_pipeline_status(FakeAudioDecoder::PIPELINE_STATUS_BUSY); - auto source_callback(base::MakeUnique<MockAudioSourceCallback>()); - ON_CALL(*source_callback, OnMoreData(_, _, _, _)) - .WillByDefault(Invoke(OnMoreData)); + ::media::MockAudioSourceCallback source_callback; + EXPECT_CALL(source_callback, OnMoreData(_, _, _, _)) + .WillRepeatedly(Invoke(OnMoreData)); // No error must be reported to source callback. - EXPECT_CALL(*source_callback, OnError()).Times(0); - stream->Start(source_callback.get()); + EXPECT_CALL(source_callback, OnError()).Times(0); + stream->Start(&source_callback); RunMessageLoopFor(5); // Make sure that one frame was pushed. EXPECT_EQ(1u, audio_decoder->pushed_buffer_count()); @@ -451,12 +441,12 @@ ASSERT_TRUE(audio_decoder); audio_decoder->set_pipeline_status(FakeAudioDecoder::PIPELINE_STATUS_ERROR); - auto source_callback(base::MakeUnique<MockAudioSourceCallback>()); - ON_CALL(*source_callback, OnMoreData(_, _, _, _)) - .WillByDefault(Invoke(OnMoreData)); + ::media::MockAudioSourceCallback source_callback; + EXPECT_CALL(source_callback, OnMoreData(_, _, _, _)) + .WillRepeatedly(Invoke(OnMoreData)); // AudioOutputStream must report error to source callback. - EXPECT_CALL(*source_callback, OnError()); - stream->Start(source_callback.get()); + EXPECT_CALL(source_callback, OnError()); + stream->Start(&source_callback); RunMessageLoopFor(2); // Make sure that AudioOutputStream attempted to push the initial frame. EXPECT_LT(0u, audio_decoder->pushed_buffer_count()); @@ -475,12 +465,12 @@ audio_decoder->set_pipeline_status( FakeAudioDecoder::PIPELINE_STATUS_ASYNC_ERROR); - auto source_callback(base::MakeUnique<MockAudioSourceCallback>()); - ON_CALL(*source_callback, OnMoreData(_, _, _, _)) - .WillByDefault(Invoke(OnMoreData)); + ::media::MockAudioSourceCallback source_callback; + EXPECT_CALL(source_callback, OnMoreData(_, _, _, _)) + .WillRepeatedly(Invoke(OnMoreData)); // AudioOutputStream must report error to source callback. - EXPECT_CALL(*source_callback, OnError()); - stream->Start(source_callback.get()); + EXPECT_CALL(source_callback, OnError()); + stream->Start(&source_callback); RunMessageLoopFor(5); // Make sure that one frame was pushed. @@ -503,6 +493,7 @@ EXPECT_EQ(1.0f, audio_decoder->volume()); stream->SetVolume(0.5); + media_thread_.FlushForTesting(); stream->GetVolume(&volume); EXPECT_EQ(0.5, volume); EXPECT_EQ(0.5f, audio_decoder->volume()); @@ -515,13 +506,13 @@ ASSERT_TRUE(stream); ASSERT_TRUE(stream->Open()); - auto source_callback(base::MakeUnique<MockAudioSourceCallback>()); - ON_CALL(*source_callback, OnMoreData(_, _, _, _)) - .WillByDefault(Invoke(OnMoreData)); - stream->Start(source_callback.get()); + ::media::MockAudioSourceCallback source_callback; + EXPECT_CALL(source_callback, OnMoreData(_, _, _, _)) + .WillRepeatedly(Invoke(OnMoreData)); + stream->Start(&source_callback); RunMessageLoopFor(2); stream->Stop(); - stream->Start(source_callback.get()); + stream->Start(&source_callback); RunMessageLoopFor(2); FakeAudioDecoder* audio_device = GetAudio(); @@ -549,14 +540,14 @@ MediaPipelineBackend::AudioDecoder::RenderingDelay(kDelayUs, kDelayTimestampUs)); - auto source_callback(base::MakeUnique<MockAudioSourceCallback>()); + ::media::MockAudioSourceCallback source_callback; const base::TimeDelta delay(base::TimeDelta::FromMicroseconds(kDelayUs)); const base::TimeTicks delay_timestamp( base::TimeTicks() + base::TimeDelta::FromMicroseconds(kDelayTimestampUs)); - EXPECT_CALL(*source_callback, OnMoreData(delay, delay_timestamp, _, _)) + EXPECT_CALL(source_callback, OnMoreData(delay, delay_timestamp, _, _)) .WillRepeatedly(Invoke(OnMoreData)); - stream->Start(source_callback.get()); + stream->Start(&source_callback); RunMessageLoopFor(2); stream->Stop(); stream->Close();
diff --git a/chromecast/media/cma/BUILD.gn b/chromecast/media/cma/BUILD.gn index 03b6384e..2ba1312 100644 --- a/chromecast/media/cma/BUILD.gn +++ b/chromecast/media/cma/BUILD.gn
@@ -14,6 +14,35 @@ ] } +source_set("test_support") { + testonly = true + sources = [ + "test/frame_generator_for_test.cc", + "test/frame_generator_for_test.h", + "test/frame_segmenter_for_test.cc", + "test/frame_segmenter_for_test.h", + "test/mock_frame_consumer.cc", + "test/mock_frame_consumer.h", + "test/mock_frame_provider.cc", + "test/mock_frame_provider.h", + "test/mock_media_pipeline_backend.cc", + "test/mock_media_pipeline_backend.h", + "test/mock_media_pipeline_backend_factory.cc", + "test/mock_media_pipeline_backend_factory.h", + ] + + deps = [ + "//base", + "//chromecast/media/cma/backend", + "//chromecast/media/cma/base", + "//media", + "//media/base:test_support", + "//testing/gmock", + "//testing/gtest", + "//ui/gfx/geometry", + ] +} + source_set("unittests") { testonly = true sources = [ @@ -27,37 +56,17 @@ "base/demuxer_stream_for_test.h", "base/multi_demuxer_stream_adapter_unittest.cc", "pipeline/audio_video_pipeline_impl_unittest.cc", - "test/frame_generator_for_test.cc", - "test/frame_generator_for_test.h", - "test/frame_segmenter_for_test.cc", - "test/frame_segmenter_for_test.h", - "test/mock_frame_consumer.cc", - "test/mock_frame_consumer.h", - "test/mock_frame_provider.cc", - "test/mock_frame_provider.h", - "test/mock_media_pipeline_backend.cc", - "test/mock_media_pipeline_backend.h", ] deps = [ + ":test_support", "//base", - "//base:i18n", "//base/test:test_support", "//chromecast/base", - "//chromecast/base/metrics:test_support", - "//chromecast/common/media:interfaces", "//chromecast/media", - "//chromecast/media/audio", - "//chromecast/media/cma/backend", - "//chromecast/media/cma/base", - "//chromecast/media/cma/pipeline", - "//chromecast/public", "//media", - "//media/base:test_support", "//testing/gmock", "//testing/gtest", - "//ui/display", - "//ui/gfx/geometry", ] data = [
diff --git a/chromecast/media/cma/backend/BUILD.gn b/chromecast/media/cma/backend/BUILD.gn index 4d096ddd..5016ccaa 100644 --- a/chromecast/media/cma/backend/BUILD.gn +++ b/chromecast/media/cma/backend/BUILD.gn
@@ -8,8 +8,9 @@ source_set("backend") { sources = [ - "media_pipeline_backend_factory.cc", "media_pipeline_backend_factory.h", + "media_pipeline_backend_factory_impl.cc", + "media_pipeline_backend_factory_impl.h", "media_pipeline_backend_manager.cc", "media_pipeline_backend_manager.h", "media_pipeline_backend_wrapper.cc",
diff --git a/chromecast/media/cma/backend/media_pipeline_backend_factory.h b/chromecast/media/cma/backend/media_pipeline_backend_factory.h index 087d20e4..2f1b010 100644 --- a/chromecast/media/cma/backend/media_pipeline_backend_factory.h +++ b/chromecast/media/cma/backend/media_pipeline_backend_factory.h
@@ -6,41 +6,23 @@ #define CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_BACKEND_FACTORY_H_ #include <memory> -#include <string> - -#include "base/macros.h" namespace chromecast { namespace media { class MediaPipelineBackend; -class MediaPipelineBackendManager; struct MediaPipelineDeviceParams; -// Creates MediaPipelineBackends using a given MediaPipelineBackendManager. +// Abstract base class to create MediaPipelineBackend. class MediaPipelineBackendFactory { public: - // TODO(slan): Use a static Create method once all of the constructor - // dependencies are removed from the internal implemenation. - explicit MediaPipelineBackendFactory( - MediaPipelineBackendManager* media_pipeline_backend_manager); - virtual ~MediaPipelineBackendFactory(); + virtual ~MediaPipelineBackendFactory() {} virtual std::unique_ptr<MediaPipelineBackend> CreateBackend( - const MediaPipelineDeviceParams& params); - - protected: - MediaPipelineBackendManager* media_pipeline_backend_manager() { - return media_pipeline_backend_manager_; - } - - private: - media::MediaPipelineBackendManager* const media_pipeline_backend_manager_; - - DISALLOW_COPY_AND_ASSIGN(MediaPipelineBackendFactory); + const MediaPipelineDeviceParams& params) = 0; }; -} // media -} // chromecast +} // namespace media +} // namespace chromecast #endif // CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_BACKEND_FACTORY_H_
diff --git a/chromecast/media/cma/backend/media_pipeline_backend_factory.cc b/chromecast/media/cma/backend/media_pipeline_backend_factory_impl.cc similarity index 81% rename from chromecast/media/cma/backend/media_pipeline_backend_factory.cc rename to chromecast/media/cma/backend/media_pipeline_backend_factory_impl.cc index d6df9d7..cb327293 100644 --- a/chromecast/media/cma/backend/media_pipeline_backend_factory.cc +++ b/chromecast/media/cma/backend/media_pipeline_backend_factory_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 "chromecast/media/cma/backend/media_pipeline_backend_factory.h" +#include "chromecast/media/cma/backend/media_pipeline_backend_factory_impl.h" #include "chromecast/media/cma/backend/media_pipeline_backend_manager.h" #include "chromecast/public/media/media_pipeline_backend.h" @@ -11,16 +11,16 @@ namespace chromecast { namespace media { -MediaPipelineBackendFactory::MediaPipelineBackendFactory( +MediaPipelineBackendFactoryImpl::MediaPipelineBackendFactoryImpl( MediaPipelineBackendManager* media_pipeline_backend_manager) : media_pipeline_backend_manager_(media_pipeline_backend_manager) { DCHECK(media_pipeline_backend_manager_); } -MediaPipelineBackendFactory::~MediaPipelineBackendFactory() {} +MediaPipelineBackendFactoryImpl::~MediaPipelineBackendFactoryImpl() {} std::unique_ptr<MediaPipelineBackend> -MediaPipelineBackendFactory::CreateBackend( +MediaPipelineBackendFactoryImpl::CreateBackend( const MediaPipelineDeviceParams& params) { return media_pipeline_backend_manager_->CreateMediaPipelineBackend(params); }
diff --git a/chromecast/media/cma/backend/media_pipeline_backend_factory_impl.h b/chromecast/media/cma/backend/media_pipeline_backend_factory_impl.h new file mode 100644 index 0000000..c2b4bbc --- /dev/null +++ b/chromecast/media/cma/backend/media_pipeline_backend_factory_impl.h
@@ -0,0 +1,44 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_BACKEND_FACTORY_IMPL_H_ +#define CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_BACKEND_FACTORY_IMPL_H_ + +#include "base/macros.h" +#include "chromecast/media/cma/backend/media_pipeline_backend_factory.h" + +namespace chromecast { +namespace media { + +class MediaPipelineBackend; +class MediaPipelineBackendManager; +struct MediaPipelineDeviceParams; + +// Creates MediaPipelineBackends using a given MediaPipelineBackendManager. +class MediaPipelineBackendFactoryImpl : public MediaPipelineBackendFactory { + public: + // TODO(slan): Use a static Create method once all of the constructor + // dependencies are removed from the internal implemenation. + explicit MediaPipelineBackendFactoryImpl( + MediaPipelineBackendManager* media_pipeline_backend_manager); + ~MediaPipelineBackendFactoryImpl() override; + + std::unique_ptr<MediaPipelineBackend> CreateBackend( + const MediaPipelineDeviceParams& params) override; + + protected: + MediaPipelineBackendManager* media_pipeline_backend_manager() { + return media_pipeline_backend_manager_; + } + + private: + media::MediaPipelineBackendManager* const media_pipeline_backend_manager_; + + DISALLOW_COPY_AND_ASSIGN(MediaPipelineBackendFactoryImpl); +}; + +} // media +} // chromecast + +#endif // CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_BACKEND_FACTORY_IMPL_H_
diff --git a/chromecast/media/cma/test/mock_media_pipeline_backend_factory.cc b/chromecast/media/cma/test/mock_media_pipeline_backend_factory.cc new file mode 100644 index 0000000..9f4d86a4 --- /dev/null +++ b/chromecast/media/cma/test/mock_media_pipeline_backend_factory.cc
@@ -0,0 +1,14 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/media/cma/test/mock_media_pipeline_backend_factory.h" + +namespace chromecast { +namespace media { + +MockMediaPipelineBackendFactory::MockMediaPipelineBackendFactory() = default; +MockMediaPipelineBackendFactory::~MockMediaPipelineBackendFactory() = default; + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/media/cma/test/mock_media_pipeline_backend_factory.h b/chromecast/media/cma/test/mock_media_pipeline_backend_factory.h new file mode 100644 index 0000000..f8d87aa --- /dev/null +++ b/chromecast/media/cma/test/mock_media_pipeline_backend_factory.h
@@ -0,0 +1,29 @@ +// 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 CHROMECAST_MEDIA_CMA_TEST_MOCK_MEDIA_PIPELINE_BACKEND_FACTORY_H_ +#define CHROMECAST_MEDIA_CMA_TEST_MOCK_MEDIA_PIPELINE_BACKEND_FACTORY_H_ + +#include "chromecast/media/cma/backend/media_pipeline_backend_factory.h" +#include "chromecast/public/media/media_pipeline_backend.h" +#include "chromecast/public/media/media_pipeline_device_params.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace chromecast { +namespace media { + +class MockMediaPipelineBackendFactory : public MediaPipelineBackendFactory { + public: + MockMediaPipelineBackendFactory(); + ~MockMediaPipelineBackendFactory() override; + + MOCK_METHOD1( + CreateBackend, + std::unique_ptr<MediaPipelineBackend>(const MediaPipelineDeviceParams&)); +}; + +} // namespace media +} // namespace chromecast + +#endif // CHROMECAST_MEDIA_CMA_TEST_MOCK_MEDIA_PIPELINE_BACKEND_FACTORY_H_
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn index f82029d..ae2fbef 100644 --- a/chromeos/BUILD.gn +++ b/chromeos/BUILD.gn
@@ -23,6 +23,7 @@ ":authpolicy_proto", ":biod_proto", ":cryptohome_proto", + ":login_manager_proto", ":media_perception_proto", ":power_manager_proto", "//base", @@ -749,6 +750,14 @@ proto_out_dir = "chromeos/dbus/cryptohome" } +proto_library("login_manager_proto") { + sources = [ + "//third_party/cros_system_api/dbus/login_manager/arc.proto", + ] + + proto_out_dir = "chromeos/dbus/login_manager" +} + proto_library("attestation_proto") { sources = [ "dbus/proto/attestation.proto",
diff --git a/chromeos/dbus/session_manager_client.cc b/chromeos/dbus/session_manager_client.cc index 2184de5..c4cda06 100644 --- a/chromeos/dbus/session_manager_client.cc +++ b/chromeos/dbus/session_manager_client.cc
@@ -25,6 +25,7 @@ #include "chromeos/cryptohome/cryptohome_parameters.h" #include "chromeos/dbus/blocking_method_caller.h" #include "chromeos/dbus/cryptohome_client.h" +#include "chromeos/dbus/login_manager/arc.pb.h" #include "components/policy/proto/device_management_backend.pb.h" #include "crypto/sha2.h" #include "dbus/bus.h" @@ -402,16 +403,20 @@ } void StartArcInstance(const cryptohome::Identification& cryptohome_id, - bool disable_boot_completed_broadcast, - bool enable_vendor_privileged, + bool skip_boot_completed_broadcast, + bool scan_vendor_priv_app, const StartArcInstanceCallback& callback) override { dbus::MethodCall method_call( login_manager::kSessionManagerInterface, login_manager::kSessionManagerStartArcInstance); dbus::MessageWriter writer(&method_call); - writer.AppendString(cryptohome_id.id()); - writer.AppendBool(disable_boot_completed_broadcast); - writer.AppendBool(enable_vendor_privileged); + + login_manager::StartArcInstanceRequest request; + request.set_account_id(cryptohome_id.id()); + request.set_skip_boot_completed_broadcast(skip_boot_completed_broadcast); + request.set_scan_vendor_priv_app(scan_vendor_priv_app); + writer.AppendProtoAsArrayOfBytes(request); + session_manager_proxy_->CallMethodWithErrorCallback( &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&SessionManagerClientImpl::OnStartArcInstanceSucceeded,
diff --git a/chromeos/dbus/session_manager_client.h b/chromeos/dbus/session_manager_client.h index bd6f3324..ea5d610 100644 --- a/chromeos/dbus/session_manager_client.h +++ b/chromeos/dbus/session_manager_client.h
@@ -301,8 +301,8 @@ base::Callback<void(StartArcInstanceResult result, const std::string& container_instance_id)>; virtual void StartArcInstance(const cryptohome::Identification& cryptohome_id, - bool disable_boot_completed_broadcast, - bool enable_vendor_privileged, + bool skip_boot_completed_broadcast, + bool scan_vendor_priv_app, const StartArcInstanceCallback& callback) = 0; // Asynchronously stops the ARC instance. Upon completion, invokes
diff --git a/chromeos/printing/printer_configuration.h b/chromeos/printing/printer_configuration.h index 18d72bc..2ed1130 100644 --- a/chromeos/printing/printer_configuration.h +++ b/chromeos/printing/printer_configuration.h
@@ -47,8 +47,9 @@ SRC_POLICY, }; - // An enumeration of printer protocols. Do not change these values as they - // are used in enums.xml. + // An enumeration of printer protocols. + // These values are written to logs. New enum values can be added, but + // existing enums must never be renumbered or deleted and reused. enum PrinterProtocol { kUnknown = 0, kUsb = 1,
diff --git a/components/BUILD.gn b/components/BUILD.gn index 1deb2cad..482b3b8 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -195,7 +195,6 @@ "//components/link_header_util:unit_tests", "//components/navigation_interception:unit_tests", "//components/network_hints/renderer:unit_tests", - "//components/offline_pages/content:unit_tests", "//components/offline_pages/content/background_loader:unit_tests", "//components/offline_pages/core:unit_tests", "//components/offline_pages/core/background:unit_tests",
diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn index c9443f48..9b890790 100644 --- a/components/arc/BUILD.gn +++ b/components/arc/BUILD.gn
@@ -73,6 +73,7 @@ "//ash/shared:app_types", "//base", "//chromeos", + "//chromeos:login_manager_proto", "//chromeos:power_manager_proto", "//components/exo", "//components/google/core/browser",
diff --git a/components/arc/arc_session.cc b/components/arc/arc_session.cc index 62c9e33..5cd62ef 100644 --- a/components/arc/arc_session.cc +++ b/components/arc/arc_session.cc
@@ -369,18 +369,18 @@ const cryptohome::Identification cryptohome_id( user_manager->GetPrimaryUser()->GetAccountId()); - bool disable_boot_completed_broadcast = + const bool skip_boot_completed_broadcast = !base::FeatureList::IsEnabled(arc::kBootCompletedBroadcastFeature); // We only enable /vendor/priv-app when voice interaction is enabled because // voice interaction service apk would be bundled in this location. - bool enable_vendor_privileged = + const bool scan_vendor_priv_app = chromeos::switches::IsVoiceInteractionEnabled(); chromeos::SessionManagerClient* session_manager_client = chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); session_manager_client->StartArcInstance( - cryptohome_id, disable_boot_completed_broadcast, enable_vendor_privileged, + cryptohome_id, skip_boot_completed_broadcast, scan_vendor_priv_app, base::Bind(&ArcSessionImpl::OnInstanceStarted, weak_factory_.GetWeakPtr(), base::Passed(&socket_fd))); }
diff --git a/components/cast_channel/BUILD.gn b/components/cast_channel/BUILD.gn new file mode 100644 index 0000000..ef44a6e --- /dev/null +++ b/components/cast_channel/BUILD.gn
@@ -0,0 +1,13 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +static_library("cast_channel") { + sources = [ + "cast_channel_enum.cc", + "cast_channel_enum.h", + ] + deps = [ + "//base", + ] +}
diff --git a/components/cast_channel/OWNERS b/components/cast_channel/OWNERS new file mode 100644 index 0000000..fc1829b --- /dev/null +++ b/components/cast_channel/OWNERS
@@ -0,0 +1,5 @@ +mfoltz@chromium.org +kmarshall@chromium.org +wez@chromium.org + +# COMPONENT: Internals>Cast>API
diff --git a/components/cast_channel/cast_channel_enum.cc b/components/cast_channel/cast_channel_enum.cc new file mode 100644 index 0000000..9e426adc --- /dev/null +++ b/components/cast_channel/cast_channel_enum.cc
@@ -0,0 +1,56 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/cast_channel/cast_channel_enum.h" + +#include "base/logging.h" + +namespace cast_channel { + +#define CAST_CHANNEL_TYPE_TO_STRING(enum) \ + case enum: \ + return #enum + +std::string ReadyStateToString(ReadyState ready_state) { + switch (ready_state) { + CAST_CHANNEL_TYPE_TO_STRING(ReadyState::NONE); + CAST_CHANNEL_TYPE_TO_STRING(ReadyState::CONNECTING); + CAST_CHANNEL_TYPE_TO_STRING(ReadyState::OPEN); + CAST_CHANNEL_TYPE_TO_STRING(ReadyState::CLOSING); + CAST_CHANNEL_TYPE_TO_STRING(ReadyState::CLOSED); + } + NOTREACHED() << "Unknown ready_state " << ReadyStateToString(ready_state); + return "Unknown ready_state"; +} + +std::string ChannelErrorToString(ChannelError channel_error) { + switch (channel_error) { + CAST_CHANNEL_TYPE_TO_STRING(ChannelError::NONE); + CAST_CHANNEL_TYPE_TO_STRING(ChannelError::CHANNEL_NOT_OPEN); + CAST_CHANNEL_TYPE_TO_STRING(ChannelError::AUTHENTICATION_ERROR); + CAST_CHANNEL_TYPE_TO_STRING(ChannelError::CONNECT_ERROR); + CAST_CHANNEL_TYPE_TO_STRING(ChannelError::CAST_SOCKET_ERROR); + CAST_CHANNEL_TYPE_TO_STRING(ChannelError::TRANSPORT_ERROR); + CAST_CHANNEL_TYPE_TO_STRING(ChannelError::INVALID_MESSAGE); + CAST_CHANNEL_TYPE_TO_STRING(ChannelError::INVALID_CHANNEL_ID); + CAST_CHANNEL_TYPE_TO_STRING(ChannelError::CONNECT_TIMEOUT); + CAST_CHANNEL_TYPE_TO_STRING(ChannelError::PING_TIMEOUT); + CAST_CHANNEL_TYPE_TO_STRING(ChannelError::UNKNOWN); + } + NOTREACHED() << "Unknown channel_error " + << ChannelErrorToString(channel_error); + return "Unknown channel_error"; +} + +std::string ChannelAuthTypeToString(ChannelAuthType channel_auth) { + switch (channel_auth) { + CAST_CHANNEL_TYPE_TO_STRING(ChannelAuthType::NONE); + CAST_CHANNEL_TYPE_TO_STRING(ChannelAuthType::SSL_VERIFIED); + } + NOTREACHED() << "Unknown channel_auth " + << ChannelAuthTypeToString(channel_auth); + return "Unknown channel_auth"; +} + +} // namespace cast_channel
diff --git a/components/cast_channel/cast_channel_enum.h b/components/cast_channel/cast_channel_enum.h new file mode 100644 index 0000000..e176cbd --- /dev/null +++ b/components/cast_channel/cast_channel_enum.h
@@ -0,0 +1,48 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_CAST_CHANNEL_CAST_CHANNEL_ENUM_H_ +#define COMPONENTS_CAST_CHANNEL_CAST_CHANNEL_ENUM_H_ + +#include <string> + +namespace cast_channel { + +// Maps to enum ReadyState in cast_channel.idl +enum class ReadyState { + NONE, + CONNECTING, + OPEN, + CLOSING, + CLOSED, +}; + +// Maps to enum ChannelError in cast_channel.idl +enum class ChannelError { + NONE, + CHANNEL_NOT_OPEN, + AUTHENTICATION_ERROR, + CONNECT_ERROR, + CAST_SOCKET_ERROR, + TRANSPORT_ERROR, + INVALID_MESSAGE, + INVALID_CHANNEL_ID, + CONNECT_TIMEOUT, + PING_TIMEOUT, + UNKNOWN, +}; + +// Maps to enum ChannelAuth in cast_channel.idl +enum class ChannelAuthType { + NONE, + SSL_VERIFIED, +}; + +std::string ReadyStateToString(ReadyState ready_state); +std::string ChannelErrorToString(ChannelError channel_error); +std::string ChannelAuthTypeToString(ChannelAuthType channel_auth); + +} // namespace cast_channel + +#endif // COMPONENTS_CAST_CHANNEL_CAST_CHANNEL_ENUM_H_
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/BrotliTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/BrotliTest.java index fefad0f1..a26fccc 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/BrotliTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/BrotliTest.java
@@ -17,8 +17,6 @@ @Override protected void setUp() throws Exception { super.setUp(); - // Load library first to create MockCertVerifier. - System.loadLibrary("cronet_tests"); assertTrue(Http2TestServer.startHttp2TestServer( getContext(), SERVER_CERT_PEM, SERVER_KEY_PKCS8_PEM)); } @@ -26,7 +24,9 @@ @Override protected void tearDown() throws Exception { assertTrue(Http2TestServer.shutdownHttp2TestServer()); - mCronetEngine.shutdown(); + if (mCronetEngine != null) { + mCronetEngine.shutdown(); + } super.tearDown(); }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc index c76189e..4985301 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
@@ -86,7 +86,9 @@ } std::vector<DataReductionProxyServer> proxies_for_http = - config_->GetProxiesForHttp(); + params::IsIncludedInHoldbackFieldTrial() + ? std::vector<DataReductionProxyServer>() + : config_->GetProxiesForHttp(); // Remove the proxies that are unsupported for this request. proxies_for_http.erase(
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc index 462c92b..5c4f2c1 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc
@@ -860,6 +860,36 @@ } } +TEST_F(DataReductionProxyDelegateTest, Holdback) { + const char kResponseHeaders[] = + "HTTP/1.1 200 OK\r\n" + "Via: 1.1 Chrome-Compression-Proxy-Suffix\r\n" + "Content-Length: 10\r\n\r\n"; + + const struct { + bool holdback; + } tests[] = { + { + true, + }, + { + false, + }, + }; + for (const auto& test : tests) { + base::FieldTrialList field_trial_list(nullptr); + ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial( + "DataCompressionProxyHoldback", test.holdback ? "Enabled" : "Control")); + + base::HistogramTester histogram_tester; + FetchURLRequest(GURL("http://example.com/path/"), nullptr, kResponseHeaders, + 10); + histogram_tester.ExpectTotalCount( + "DataReductionProxy.SuccessfulRequestCompletionCounts", + test.holdback ? 0 : 1); + } +} + TEST_F(DataReductionProxyDelegateTest, OnCompletedSizeFor304) { int64_t baseline_received_bytes = total_received_bytes(); int64_t baseline_original_received_bytes = total_original_received_bytes();
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc index dd29ebf..df46721 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
@@ -164,6 +164,9 @@ // Saver proxy. void VerifyHttpRequestHeaders(bool via_chrome_proxy, const net::HttpRequestHeaders& headers) { + // If holdback is enabled, then |via_chrome_proxy| should be false. + DCHECK(!params::IsIncludedInHoldbackFieldTrial() || !via_chrome_proxy); + if (via_chrome_proxy) { DCHECK(headers.HasHeader(chrome_proxy_ect_header())); std::string chrome_proxy_header_value; @@ -283,16 +286,17 @@ DataReductionProxyData::ClearData(request); if (params::IsIncludedInHoldbackFieldTrial()) { - if (!WasEligibleWithoutHoldback(*request, proxy_info, proxy_retry_info)) - return; - // For the holdback field trial, still log UMA as if the proxy was used. - data = DataReductionProxyData::GetDataAndCreateIfNecessary(request); - if (data) - data->set_used_data_reduction_proxy(true); - - headers->RemoveHeader(chrome_proxy_header()); - VerifyHttpRequestHeaders(false, *headers); - return; + if (WasEligibleWithoutHoldback(*request, proxy_info, proxy_retry_info)) { + // For the holdback field trial, still log UMA as if the proxy was used. + data = DataReductionProxyData::GetDataAndCreateIfNecessary(request); + if (data) + data->set_used_data_reduction_proxy(true); + } + // If holdback is enabled, |proxy_info| must not contain a data reduction + // proxy. + DCHECK(proxy_info.is_empty() || + !data_reduction_proxy_config_->IsDataReductionProxy( + proxy_info.proxy_server(), nullptr)); } bool using_data_reduction_proxy = true; @@ -306,6 +310,9 @@ proxy_info.proxy_server(), nullptr)) { using_data_reduction_proxy = false; } + // If holdback is enabled, |using_data_reduction_proxy| must be false. + DCHECK(!params::IsIncludedInHoldbackFieldTrial() || + !using_data_reduction_proxy); LoFiDecider* lofi_decider = nullptr; if (data_reduction_proxy_io_data_)
diff --git a/components/download/internal/BUILD.gn b/components/download/internal/BUILD.gn index d1e1e43..dc74506 100644 --- a/components/download/internal/BUILD.gn +++ b/components/download/internal/BUILD.gn
@@ -21,6 +21,8 @@ "download_driver.h", "download_service_impl.cc", "download_service_impl.h", + "download_store.cc", + "download_store.h", "driver_entry.cc", "driver_entry.h", "entry.cc", @@ -28,8 +30,8 @@ "model.h", "model_impl.cc", "model_impl.h", - "noop_store.cc", - "noop_store.h", + "proto_conversions.cc", + "proto_conversions.h", "scheduler/battery_listener.cc", "scheduler/battery_listener.h", "scheduler/network_listener.cc", @@ -39,7 +41,9 @@ deps = [ "//base", + "//components/download/internal/proto", "//components/download/public", + "//components/leveldb_proto", "//net", ] } @@ -50,7 +54,9 @@ visibility = [ "//components/download:unit_tests" ] sources = [ + "download_store_unittest.cc", "model_impl_unittest.cc", + "proto_conversions_unittest.cc", "scheduler/battery_listener_unittest.cc", "scheduler/network_listener_unittest.cc", ] @@ -58,7 +64,9 @@ deps = [ ":internal", "//base/test:test_support", + "//components/download/internal/proto", "//components/download/internal/test:test_support", + "//components/leveldb_proto:test_support", "//testing/gmock", "//testing/gtest", ]
diff --git a/components/download/internal/DEPS b/components/download/internal/DEPS index 4ca86d9b..6a99578 100644 --- a/components/download/internal/DEPS +++ b/components/download/internal/DEPS
@@ -1,6 +1,7 @@ include_rules = [ "-components/download/content", "-content", + "+components/leveldb_proto", "+base", "+net", ]
diff --git a/components/download/internal/download_store.cc b/components/download/internal/download_store.cc new file mode 100644 index 0000000..a7890e89 --- /dev/null +++ b/components/download/internal/download_store.cc
@@ -0,0 +1,89 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/download/internal/download_store.h" + +#include "base/bind.h" +#include "base/callback_helpers.h" +#include "base/memory/ptr_util.h" +#include "components/download/internal/entry.h" +#include "components/download/internal/proto/entry.pb.h" +#include "components/download/internal/proto_conversions.h" +#include "components/leveldb_proto/proto_database_impl.h" + +namespace download { + +namespace { + +const char kDatabaseClientName[] = "DownloadService"; +using KeyVector = std::vector<std::string>; +using ProtoEntryVector = std::vector<protodb::Entry>; +using KeyProtoEntryVector = std::vector<std::pair<std::string, protodb::Entry>>; + +} // namespace + +DownloadStore::DownloadStore( + const base::FilePath& database_dir, + std::unique_ptr<leveldb_proto::ProtoDatabase<protodb::Entry>> db) + : db_(std::move(db)), + database_dir_(database_dir), + is_initialized_(false), + weak_factory_(this) {} + +DownloadStore::~DownloadStore() = default; + +bool DownloadStore::IsInitialized() { + return is_initialized_; +} + +void DownloadStore::Initialize(InitCallback callback) { + DCHECK(!IsInitialized()); + db_->InitWithOptions( + kDatabaseClientName, leveldb_proto::Options(database_dir_), + base::BindOnce(&DownloadStore::OnDatabaseInited, + weak_factory_.GetWeakPtr(), std::move(callback))); +} + +void DownloadStore::OnDatabaseInited(InitCallback callback, bool success) { + if (!success) { + std::move(callback).Run(success, base::MakeUnique<std::vector<Entry>>()); + return; + } + + db_->LoadEntries(base::BindOnce(&DownloadStore::OnDatabaseLoaded, + weak_factory_.GetWeakPtr(), + std::move(callback))); +} + +void DownloadStore::OnDatabaseLoaded(InitCallback callback, + bool success, + std::unique_ptr<ProtoEntryVector> protos) { + if (!success) { + std::move(callback).Run(success, base::MakeUnique<std::vector<Entry>>()); + return; + } + + auto entries = ProtoConversions::EntryVectorFromProto(std::move(protos)); + is_initialized_ = true; + std::move(callback).Run(success, std::move(entries)); +} + +void DownloadStore::Update(const Entry& entry, StoreCallback callback) { + DCHECK(IsInitialized()); + auto entries_to_save = base::MakeUnique<KeyProtoEntryVector>(); + protodb::Entry proto = ProtoConversions::EntryToProto(entry); + entries_to_save->emplace_back(entry.guid, std::move(proto)); + db_->UpdateEntries(std::move(entries_to_save), base::MakeUnique<KeyVector>(), + std::move(callback)); +} + +void DownloadStore::Remove(const std::string& guid, StoreCallback callback) { + DCHECK(IsInitialized()); + auto keys_to_remove = base::MakeUnique<KeyVector>(); + keys_to_remove->push_back(guid); + db_->UpdateEntries(base::MakeUnique<KeyProtoEntryVector>(), + std::move(keys_to_remove), std::move(callback)); +} + +} // namespace download
diff --git a/components/download/internal/download_store.h b/components/download/internal/download_store.h new file mode 100644 index 0000000..e662e80c --- /dev/null +++ b/components/download/internal/download_store.h
@@ -0,0 +1,58 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_DOWNLOAD_INTERNAL_DOWNLOAD_STORE_H_ +#define COMPONENTS_DOWNLOAD_INTERNAL_DOWNLOAD_STORE_H_ + +#include <string> +#include <vector> + +#include "base/files/file_path.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "components/download/internal/store.h" +#include "components/leveldb_proto/proto_database.h" + +namespace protodb { +class Entry; + +} // namespace + +namespace download { + +// DownloadStore provides a layer around a LevelDB proto database that persists +// the download request, scheduling params and metadata to the disk. The data is +// read during initialization and presented to the caller after converting to +// Entry entries. +class DownloadStore : public Store { + public: + DownloadStore( + const base::FilePath& database_dir, + std::unique_ptr<leveldb_proto::ProtoDatabase<protodb::Entry>> db); + ~DownloadStore() override; + + // Store implementation. + bool IsInitialized() override; + void Initialize(InitCallback callback) override; + void Update(const Entry& entry, StoreCallback callback) override; + void Remove(const std::string& guid, StoreCallback callback) override; + + private: + void OnDatabaseInited(InitCallback callback, bool success); + void OnDatabaseLoaded(InitCallback callback, + bool success, + std::unique_ptr<std::vector<protodb::Entry>> protos); + + std::unique_ptr<leveldb_proto::ProtoDatabase<protodb::Entry>> db_; + base::FilePath database_dir_; + bool is_initialized_; + + base::WeakPtrFactory<DownloadStore> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(DownloadStore); +}; + +} // namespace download + +#endif // COMPONENTS_DOWNLOAD_INTERNAL_DOWNLOAD_STORE_H_
diff --git a/components/download/internal/download_store_unittest.cc b/components/download/internal/download_store_unittest.cc new file mode 100644 index 0000000..6a69d5b5 --- /dev/null +++ b/components/download/internal/download_store_unittest.cc
@@ -0,0 +1,240 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/download/internal/download_store.h" + +#include <algorithm> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/guid.h" +#include "base/memory/ptr_util.h" +#include "components/download/internal/entry.h" +#include "components/download/internal/proto/entry.pb.h" +#include "components/download/internal/proto_conversions.h" +#include "components/download/internal/test/entry_utils.h" +#include "components/leveldb_proto/testing/fake_db.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; + +namespace download { + +class DownloadStoreTest : public testing::Test { + public: + DownloadStoreTest() : db_(nullptr) {} + + ~DownloadStoreTest() override = default; + + void CreateDatabase() { + auto db = base::MakeUnique<leveldb_proto::test::FakeDB<protodb::Entry>>( + &db_entries_); + db_ = db.get(); + store_.reset(new DownloadStore( + base::FilePath(FILE_PATH_LITERAL("/test/db/fakepath")), std::move(db))); + } + + void InitCallback(std::vector<Entry>* loaded_entries, + bool success, + std::unique_ptr<std::vector<Entry>> entries) { + loaded_entries->swap(*entries); + } + + void LoadCallback(std::vector<protodb::Entry>* loaded_entries, + bool success, + std::unique_ptr<std::vector<protodb::Entry>> entries) { + loaded_entries->swap(*entries); + } + + MOCK_METHOD1(StoreCallback, void(bool)); + + void PrepopulateSampleEntries() { + Entry item1 = test::BuildEntry(DownloadClient::TEST, base::GenerateGUID()); + Entry item2 = test::BuildEntry(DownloadClient::TEST, base::GenerateGUID()); + db_entries_.insert( + std::make_pair(item1.guid, ProtoConversions::EntryToProto(item1))); + db_entries_.insert( + std::make_pair(item2.guid, ProtoConversions::EntryToProto(item2))); + } + + protected: + std::map<std::string, protodb::Entry> db_entries_; + leveldb_proto::test::FakeDB<protodb::Entry>* db_; + std::unique_ptr<DownloadStore> store_; + + DISALLOW_COPY_AND_ASSIGN(DownloadStoreTest); +}; + +TEST_F(DownloadStoreTest, Initialize) { + PrepopulateSampleEntries(); + CreateDatabase(); + ASSERT_FALSE(store_->IsInitialized()); + + std::vector<Entry> preloaded_entries; + store_->Initialize(base::Bind(&DownloadStoreTest::InitCallback, + base::Unretained(this), &preloaded_entries)); + db_->InitCallback(true); + db_->LoadCallback(true); + + ASSERT_TRUE(store_->IsInitialized()); + ASSERT_EQ(2u, preloaded_entries.size()); +} + +TEST_F(DownloadStoreTest, Update) { + PrepopulateSampleEntries(); + CreateDatabase(); + + std::vector<Entry> preloaded_entries; + store_->Initialize(base::Bind(&DownloadStoreTest::InitCallback, + base::Unretained(this), &preloaded_entries)); + db_->InitCallback(true); + db_->LoadCallback(true); + ASSERT_TRUE(store_->IsInitialized()); + ASSERT_EQ(2u, preloaded_entries.size()); + + Entry item1 = test::BuildEntry(DownloadClient::TEST, base::GenerateGUID()); + Entry item2 = test::BuildEntry(DownloadClient::TEST, base::GenerateGUID()); + EXPECT_CALL(*this, StoreCallback(true)).Times(2); + store_->Update(item1, base::Bind(&DownloadStoreTest::StoreCallback, + base::Unretained(this))); + db_->UpdateCallback(true); + store_->Update(item2, base::Bind(&DownloadStoreTest::StoreCallback, + base::Unretained(this))); + db_->UpdateCallback(true); + + // Query the database directly and check for the entry. + auto protos = base::MakeUnique<std::vector<protodb::Entry>>(); + db_->LoadEntries(base::Bind(&DownloadStoreTest::LoadCallback, + base::Unretained(this), protos.get())); + db_->LoadCallback(true); + ASSERT_EQ(4u, protos->size()); + ASSERT_TRUE(test::CompareEntryList( + {preloaded_entries[0], preloaded_entries[1], item1, item2}, + *ProtoConversions::EntryVectorFromProto(std::move(protos)))); +} + +TEST_F(DownloadStoreTest, Remove) { + PrepopulateSampleEntries(); + CreateDatabase(); + + std::vector<Entry> preloaded_entries; + store_->Initialize(base::Bind(&DownloadStoreTest::InitCallback, + base::Unretained(this), &preloaded_entries)); + db_->InitCallback(true); + db_->LoadCallback(true); + ASSERT_EQ(2u, preloaded_entries.size()); + + // Remove the entry. + EXPECT_CALL(*this, StoreCallback(true)).Times(1); + store_->Remove( + preloaded_entries[0].guid, + base::Bind(&DownloadStoreTest::StoreCallback, base::Unretained(this))); + db_->UpdateCallback(true); + + // Query the database directly and check for the entry removed. + auto protos = base::MakeUnique<std::vector<protodb::Entry>>(); + db_->LoadEntries(base::Bind(&DownloadStoreTest::LoadCallback, + base::Unretained(this), protos.get())); + db_->LoadCallback(true); + ASSERT_EQ(1u, protos->size()); + ASSERT_TRUE(test::CompareEntryList( + {preloaded_entries[1]}, + *ProtoConversions::EntryVectorFromProto(std::move(protos)))); +} + +TEST_F(DownloadStoreTest, InitializeFailed) { + PrepopulateSampleEntries(); + CreateDatabase(); + + std::vector<Entry> preloaded_entries; + store_->Initialize(base::Bind(&DownloadStoreTest::InitCallback, + base::Unretained(this), &preloaded_entries)); + db_->InitCallback(false); + ASSERT_FALSE(store_->IsInitialized()); + ASSERT_TRUE(preloaded_entries.empty()); +} + +TEST_F(DownloadStoreTest, InitialLoadFailed) { + PrepopulateSampleEntries(); + CreateDatabase(); + + std::vector<Entry> preloaded_entries; + store_->Initialize(base::Bind(&DownloadStoreTest::InitCallback, + base::Unretained(this), &preloaded_entries)); + db_->InitCallback(true); + db_->LoadCallback(false); + ASSERT_FALSE(store_->IsInitialized()); + ASSERT_TRUE(preloaded_entries.empty()); +} + +TEST_F(DownloadStoreTest, UnsuccessfulUpdateOrRemove) { + Entry item1 = test::BuildEntry(DownloadClient::TEST, base::GenerateGUID()); + CreateDatabase(); + + std::vector<Entry> entries; + store_->Initialize(base::Bind(&DownloadStoreTest::InitCallback, + base::Unretained(this), &entries)); + db_->InitCallback(true); + db_->LoadCallback(true); + ASSERT_TRUE(store_->IsInitialized()); + ASSERT_TRUE(entries.empty()); + + // Update failed. + EXPECT_CALL(*this, StoreCallback(false)).Times(1); + store_->Update(item1, base::Bind(&DownloadStoreTest::StoreCallback, + base::Unretained(this))); + db_->UpdateCallback(false); + + // Remove failed. + EXPECT_CALL(*this, StoreCallback(false)).Times(1); + store_->Remove(item1.guid, base::Bind(&DownloadStoreTest::StoreCallback, + base::Unretained(this))); + db_->UpdateCallback(false); +} + +TEST_F(DownloadStoreTest, AddThenRemove) { + CreateDatabase(); + + std::vector<Entry> entries; + store_->Initialize(base::Bind(&DownloadStoreTest::InitCallback, + base::Unretained(this), &entries)); + db_->InitCallback(true); + db_->LoadCallback(true); + ASSERT_TRUE(entries.empty()); + + Entry item1 = test::BuildEntry(DownloadClient::TEST, base::GenerateGUID()); + Entry item2 = test::BuildEntry(DownloadClient::TEST, base::GenerateGUID()); + EXPECT_CALL(*this, StoreCallback(true)).Times(2); + store_->Update(item1, base::Bind(&DownloadStoreTest::StoreCallback, + base::Unretained(this))); + db_->UpdateCallback(true); + store_->Update(item2, base::Bind(&DownloadStoreTest::StoreCallback, + base::Unretained(this))); + db_->UpdateCallback(true); + + // Query the database directly and check for the entry. + auto protos = base::MakeUnique<std::vector<protodb::Entry>>(); + db_->LoadEntries(base::Bind(&DownloadStoreTest::LoadCallback, + base::Unretained(this), protos.get())); + db_->LoadCallback(true); + ASSERT_EQ(2u, protos->size()); + + // Remove the entry. + EXPECT_CALL(*this, StoreCallback(true)).Times(1); + store_->Remove(item1.guid, base::Bind(&DownloadStoreTest::StoreCallback, + base::Unretained(this))); + db_->UpdateCallback(true); + + // Query the database directly and check for the entry removed. + protos->clear(); + db_->LoadEntries(base::Bind(&DownloadStoreTest::LoadCallback, + base::Unretained(this), protos.get())); + db_->LoadCallback(true); + ASSERT_EQ(1u, protos->size()); + ASSERT_TRUE(test::CompareEntryList( + {item2}, *ProtoConversions::EntryVectorFromProto(std::move(protos)))); +} + +} // namespace download
diff --git a/components/download/internal/model.h b/components/download/internal/model.h index ce5de88e..d7f6d10 100644 --- a/components/download/internal/model.h +++ b/components/download/internal/model.h
@@ -32,11 +32,6 @@ // callback. If |success| is true it can be accessed now. virtual void OnInitialized(bool success) = 0; - // Called asynchronously in response to a Model::Destroy call. If |success| - // is |false|, destruction of the Model and/or the underlying Store failed. - // Destruction of the Model is effectively complete after this callback. - virtual void OnDestroyed(bool success) = 0; - // Called when an Entry addition is complete. |success| determines whether // or not the entry has been successfully persisted to the Store. virtual void OnItemAdded(bool success, @@ -64,9 +59,6 @@ // The Model can be used after that call. virtual void Initialize() = 0; - // Destroys the Model. Client::OnDestroyed() will be called in response. - virtual void Destroy() = 0; - // Adds |entry| to this Model and attempts to write |entry| to the Store. // Client::OnItemAdded() will be called in response asynchronously. virtual void Add(const Entry& entry) = 0;
diff --git a/components/download/internal/model_impl.cc b/components/download/internal/model_impl.cc index f061b5d..3ab384b 100644 --- a/components/download/internal/model_impl.cc +++ b/components/download/internal/model_impl.cc
@@ -20,13 +20,8 @@ void ModelImpl::Initialize() { DCHECK(!store_->IsInitialized()); - store_->Initialize(base::Bind(&ModelImpl::OnInitializedFinished, - weak_ptr_factory_.GetWeakPtr())); -} - -void ModelImpl::Destroy() { - store_->Destroy(base::Bind(&ModelImpl::OnDestroyFinished, - weak_ptr_factory_.GetWeakPtr())); + store_->Initialize(base::BindOnce(&ModelImpl::OnInitializedFinished, + weak_ptr_factory_.GetWeakPtr())); } void ModelImpl::Add(const Entry& entry) { @@ -35,9 +30,9 @@ entries_.emplace(entry.guid, base::MakeUnique<Entry>(entry)); - store_->Update(entry, base::Bind(&ModelImpl::OnAddFinished, - weak_ptr_factory_.GetWeakPtr(), entry.client, - entry.guid)); + store_->Update(entry, base::BindOnce(&ModelImpl::OnAddFinished, + weak_ptr_factory_.GetWeakPtr(), + entry.client, entry.guid)); } void ModelImpl::Update(const Entry& entry) { @@ -45,9 +40,9 @@ DCHECK(entries_.find(entry.guid) != entries_.end()); entries_[entry.guid] = base::MakeUnique<Entry>(entry); - store_->Update(entry, base::Bind(&ModelImpl::OnUpdateFinished, - weak_ptr_factory_.GetWeakPtr(), entry.client, - entry.guid)); + store_->Update(entry, base::BindOnce(&ModelImpl::OnUpdateFinished, + weak_ptr_factory_.GetWeakPtr(), + entry.client, entry.guid)); } void ModelImpl::Remove(const std::string& guid) { @@ -59,8 +54,8 @@ DownloadClient client = it->second->client; entries_.erase(it); store_->Remove(guid, - base::Bind(&ModelImpl::OnRemoveFinished, - weak_ptr_factory_.GetWeakPtr(), client, guid)); + base::BindOnce(&ModelImpl::OnRemoveFinished, + weak_ptr_factory_.GetWeakPtr(), client, guid)); } Entry* ModelImpl::Get(const std::string& guid) { @@ -90,12 +85,6 @@ client_->OnInitialized(true); } -void ModelImpl::OnDestroyFinished(bool success) { - store_.reset(); - entries_.clear(); - client_->OnDestroyed(success); -} - void ModelImpl::OnAddFinished(DownloadClient client, const std::string& guid, bool success) {
diff --git a/components/download/internal/model_impl.h b/components/download/internal/model_impl.h index 8c785019..3f4d198 100644 --- a/components/download/internal/model_impl.h +++ b/components/download/internal/model_impl.h
@@ -28,7 +28,6 @@ // Model implementation. void Initialize() override; - void Destroy() override; void Add(const Entry& entry) override; void Update(const Entry& entry) override; void Remove(const std::string& guid) override; @@ -40,7 +39,6 @@ void OnInitializedFinished(bool success, std::unique_ptr<std::vector<Entry>> entries); - void OnDestroyFinished(bool success); void OnAddFinished(DownloadClient client, const std::string& guid, bool success);
diff --git a/components/download/internal/model_impl_unittest.cc b/components/download/internal/model_impl_unittest.cc index 19a78391..c0b3f215 100644 --- a/components/download/internal/model_impl_unittest.cc +++ b/components/download/internal/model_impl_unittest.cc
@@ -52,15 +52,10 @@ TEST_F(DownloadServiceModelImplTest, SuccessfulLifecycle) { InSequence sequence; EXPECT_CALL(client_, OnInitialized(true)).Times(1); - EXPECT_CALL(client_, OnDestroyed(true)).Times(1); model_->Initialize(); EXPECT_TRUE(store_->init_called()); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>()); - - model_->Destroy(); - EXPECT_TRUE(store_->destroy_called()); - store_->TriggerDestroy(true); } TEST_F(DownloadServiceModelImplTest, SuccessfulInitWithEntries) { @@ -75,8 +70,8 @@ EXPECT_TRUE(store_->init_called()); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); - EXPECT_TRUE(test::SuperficialEntryCompare(&entry1, model_->Get(entry1.guid))); - EXPECT_TRUE(test::SuperficialEntryCompare(&entry2, model_->Get(entry2.guid))); + EXPECT_TRUE(test::CompareEntry(&entry1, model_->Get(entry1.guid))); + EXPECT_TRUE(test::CompareEntry(&entry2, model_->Get(entry2.guid))); } TEST_F(DownloadServiceModelImplTest, BadInit) { @@ -87,20 +82,6 @@ store_->TriggerInit(false, base::MakeUnique<std::vector<Entry>>()); } -TEST_F(DownloadServiceModelImplTest, BadDestroy) { - InSequence sequence; - EXPECT_CALL(client_, OnInitialized(true)).Times(1); - EXPECT_CALL(client_, OnDestroyed(false)).Times(1); - - model_->Initialize(); - EXPECT_TRUE(store_->init_called()); - store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>()); - - model_->Destroy(); - EXPECT_TRUE(store_->destroy_called()); - store_->TriggerDestroy(false); -} - TEST_F(DownloadServiceModelImplTest, Add) { Entry entry1 = test::BuildEntry(DownloadClient::TEST, base::GenerateGUID()); Entry entry2 = test::BuildEntry(DownloadClient::TEST, base::GenerateGUID()); @@ -114,15 +95,13 @@ store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>()); model_->Add(entry1); - EXPECT_TRUE(test::SuperficialEntryCompare(&entry1, model_->Get(entry1.guid))); - EXPECT_TRUE( - test::SuperficialEntryCompare(&entry1, store_->LastUpdatedEntry())); + EXPECT_TRUE(test::CompareEntry(&entry1, model_->Get(entry1.guid))); + EXPECT_TRUE(test::CompareEntry(&entry1, store_->LastUpdatedEntry())); store_->TriggerUpdate(true); model_->Add(entry2); - EXPECT_TRUE(test::SuperficialEntryCompare(&entry2, model_->Get(entry2.guid))); - EXPECT_TRUE( - test::SuperficialEntryCompare(&entry2, store_->LastUpdatedEntry())); + EXPECT_TRUE(test::CompareEntry(&entry2, model_->Get(entry2.guid))); + EXPECT_TRUE(test::CompareEntry(&entry2, store_->LastUpdatedEntry())); store_->TriggerUpdate(false); EXPECT_EQ(nullptr, model_->Get(entry2.guid)); @@ -150,18 +129,16 @@ store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); model_->Update(entry2); - EXPECT_TRUE(test::SuperficialEntryCompare(&entry2, model_->Get(entry2.guid))); - EXPECT_TRUE( - test::SuperficialEntryCompare(&entry2, store_->LastUpdatedEntry())); + EXPECT_TRUE(test::CompareEntry(&entry2, model_->Get(entry2.guid))); + EXPECT_TRUE(test::CompareEntry(&entry2, store_->LastUpdatedEntry())); store_->TriggerUpdate(true); model_->Update(entry3); - EXPECT_TRUE(test::SuperficialEntryCompare(&entry3, model_->Get(entry3.guid))); - EXPECT_TRUE( - test::SuperficialEntryCompare(&entry3, store_->LastUpdatedEntry())); + EXPECT_TRUE(test::CompareEntry(&entry3, model_->Get(entry3.guid))); + EXPECT_TRUE(test::CompareEntry(&entry3, store_->LastUpdatedEntry())); store_->TriggerUpdate(false); - EXPECT_TRUE(test::SuperficialEntryCompare(&entry3, model_->Get(entry3.guid))); + EXPECT_TRUE(test::CompareEntry(&entry3, model_->Get(entry3.guid))); } TEST_F(DownloadServiceModelImplTest, Remove) { @@ -201,7 +178,7 @@ model_->Initialize(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); - EXPECT_TRUE(test::SuperficialEntryCompare(&entry, model_->Get(entry.guid))); + EXPECT_TRUE(test::CompareEntry(&entry, model_->Get(entry.guid))); EXPECT_EQ(nullptr, model_->Get(base::GenerateGUID())); } @@ -218,8 +195,7 @@ std::vector<Entry*> expected_peek = {&entry1, &entry2}; - EXPECT_TRUE( - test::SuperficialEntryListCompare(expected_peek, model_->PeekEntries())); + EXPECT_TRUE(test::CompareEntryList(expected_peek, model_->PeekEntries())); } TEST_F(DownloadServiceModelImplTest, TestRemoveAfterAdd) { @@ -234,7 +210,7 @@ store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>()); model_->Add(entry); - EXPECT_TRUE(test::SuperficialEntryCompare(&entry, model_->Get(entry.guid))); + EXPECT_TRUE(test::CompareEntry(&entry, model_->Get(entry.guid))); model_->Remove(entry.guid); EXPECT_EQ(nullptr, model_->Get(entry.guid)); @@ -259,10 +235,10 @@ model_->Initialize(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); - EXPECT_TRUE(test::SuperficialEntryCompare(&entry1, model_->Get(entry1.guid))); + EXPECT_TRUE(test::CompareEntry(&entry1, model_->Get(entry1.guid))); model_->Update(entry2); - EXPECT_TRUE(test::SuperficialEntryCompare(&entry2, model_->Get(entry2.guid))); + EXPECT_TRUE(test::CompareEntry(&entry2, model_->Get(entry2.guid))); model_->Remove(entry2.guid); EXPECT_EQ(nullptr, model_->Get(entry2.guid));
diff --git a/components/download/internal/proto/BUILD.gn b/components/download/internal/proto/BUILD.gn new file mode 100644 index 0000000..c9132cb --- /dev/null +++ b/components/download/internal/proto/BUILD.gn
@@ -0,0 +1,13 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//third_party/protobuf/proto_library.gni") + +proto_library("proto") { + sources = [ + "entry.proto", + "request.proto", + "scheduling.proto", + ] +}
diff --git a/components/download/internal/proto/entry.proto b/components/download/internal/proto/entry.proto new file mode 100644 index 0000000..d5f9dfed --- /dev/null +++ b/components/download/internal/proto/entry.proto
@@ -0,0 +1,47 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +syntax = "proto2"; + +option optimize_for = LITE_RUNTIME; + +package protodb; + +import "request.proto"; +import "scheduling.proto"; + +// This should stay in sync with the DownloadClient enum +// (components/download/public/clients.h). +enum DownloadClient { + INVALID = 0; + TEST = 1; + OFFLINE_PAGE_PREFETCH = 2; + BOUNDARY = 3; +} + +// Stores the request params, internal state, metrics and metadata associated +// with a download request. +message Entry { + // This should stay in sync with the State enum + // (components/download/internal/entry.h). + enum State { + NEW = 0; + AVAILABLE = 1; + ACTIVE = 2; + PAUSED = 3; + COMPLETE = 4; + WATCHDOG = 5; + } + + // Identification Parameters. + optional DownloadClient name_space = 1; + optional string guid = 2; + + // Requested Parameters. + optional SchedulingParams scheduling_params = 3; + optional RequestParams request_params = 4; + + // Internal Tracking State. + optional State state = 5; +}
diff --git a/components/download/internal/proto/request.proto b/components/download/internal/proto/request.proto new file mode 100644 index 0000000..173c6856 --- /dev/null +++ b/components/download/internal/proto/request.proto
@@ -0,0 +1,21 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +syntax = "proto2"; + +option optimize_for = LITE_RUNTIME; + +package protodb; + +message RequestHeader { + optional string key = 1; + optional string value = 2; +} + +// Stores the HTTP request params associated with a download request. +message RequestParams { + optional string url = 1; + optional string method = 2; + repeated RequestHeader headers = 3; +}
diff --git a/components/download/internal/proto/scheduling.proto b/components/download/internal/proto/scheduling.proto new file mode 100644 index 0000000..2b8cc7ac --- /dev/null +++ b/components/download/internal/proto/scheduling.proto
@@ -0,0 +1,43 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +syntax = "proto2"; + +option optimize_for = LITE_RUNTIME; + +package protodb; + +// Stores the scheduling params associated with a download request. +message SchedulingParams { + // This should stay in sync with the NetworkRequirements enum + // (components/download/public/download_params.h). + enum NetworkRequirements { + NONE = 0; + OPTIMISTIC = 1; + UNMETERED = 2; + } + + // This should stay in sync with the BatteryRequirements enum + // (components/download/public/download_params.h). + enum BatteryRequirements { + BATTERY_INSENSITIVE = 0; + BATTERY_SENSITIVE = 1; + } + + // This should stay in sync with the Priority enum + // (components/download/public/download_params.h). + enum Priority { + LOW = 0; + NORMAL = 1; + HIGH = 2; + UI = 3; + } + + // Uses internal time representation. + optional int64 cancel_time = 2; + + optional Priority priority = 3; + optional NetworkRequirements network_requirements = 4; + optional BatteryRequirements battery_requirements = 5; +}
diff --git a/components/download/internal/proto_conversions.cc b/components/download/internal/proto_conversions.cc new file mode 100644 index 0000000..dc4187a --- /dev/null +++ b/components/download/internal/proto_conversions.cc
@@ -0,0 +1,285 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <utility> + +#include "base/memory/ptr_util.h" +#include "base/time/time.h" +#include "components/download/internal/proto_conversions.h" +#include "net/http/http_request_headers.h" + +namespace download { + +protodb::Entry_State ProtoConversions::RequestStateToProto(Entry::State state) { + switch (state) { + case Entry::State::NEW: + return protodb::Entry_State_NEW; + case Entry::State::AVAILABLE: + return protodb::Entry_State_AVAILABLE; + case Entry::State::ACTIVE: + return protodb::Entry_State_ACTIVE; + case Entry::State::PAUSED: + return protodb::Entry_State_PAUSED; + case Entry::State::COMPLETE: + return protodb::Entry_State_COMPLETE; + case Entry::State::WATCHDOG: + return protodb::Entry_State_WATCHDOG; + } + + NOTREACHED(); + return protodb::Entry_State_NEW; +} + +Entry::State ProtoConversions::RequestStateFromProto( + protodb::Entry_State state) { + switch (state) { + case protodb::Entry_State_NEW: + return Entry::State::NEW; + case protodb::Entry_State_AVAILABLE: + return Entry::State::AVAILABLE; + case protodb::Entry_State_ACTIVE: + return Entry::State::ACTIVE; + case protodb::Entry_State_PAUSED: + return Entry::State::PAUSED; + case protodb::Entry_State_COMPLETE: + return Entry::State::COMPLETE; + case protodb::Entry_State_WATCHDOG: + return Entry::State::WATCHDOG; + } + + NOTREACHED(); + return Entry::State::NEW; +} + +protodb::DownloadClient ProtoConversions::DownloadClientToProto( + DownloadClient client) { + switch (client) { + case DownloadClient::INVALID: + return protodb::DownloadClient::INVALID; + case DownloadClient::TEST: + return protodb::DownloadClient::TEST; + case DownloadClient::OFFLINE_PAGE_PREFETCH: + return protodb::DownloadClient::OFFLINE_PAGE_PREFETCH; + case DownloadClient::BOUNDARY: + return protodb::DownloadClient::BOUNDARY; + } + + NOTREACHED(); + return protodb::DownloadClient::INVALID; +} + +DownloadClient ProtoConversions::DownloadClientFromProto( + protodb::DownloadClient client) { + switch (client) { + case protodb::DownloadClient::INVALID: + return DownloadClient::INVALID; + case protodb::DownloadClient::TEST: + return DownloadClient::TEST; + case protodb::DownloadClient::OFFLINE_PAGE_PREFETCH: + return DownloadClient::OFFLINE_PAGE_PREFETCH; + case protodb::DownloadClient::BOUNDARY: + return DownloadClient::BOUNDARY; + } + + NOTREACHED(); + return DownloadClient::INVALID; +} + +SchedulingParams::NetworkRequirements +ProtoConversions::NetworkRequirementsFromProto( + protodb::SchedulingParams_NetworkRequirements network_requirements) { + switch (network_requirements) { + case protodb::SchedulingParams_NetworkRequirements_NONE: + return SchedulingParams::NetworkRequirements::NONE; + case protodb::SchedulingParams_NetworkRequirements_OPTIMISTIC: + return SchedulingParams::NetworkRequirements::OPTIMISTIC; + case protodb::SchedulingParams_NetworkRequirements_UNMETERED: + return SchedulingParams::NetworkRequirements::UNMETERED; + } + + NOTREACHED(); + return SchedulingParams::NetworkRequirements::NONE; +} + +protodb::SchedulingParams_NetworkRequirements +ProtoConversions::NetworkRequirementsToProto( + SchedulingParams::NetworkRequirements network_requirements) { + switch (network_requirements) { + case SchedulingParams::NetworkRequirements::NONE: + return protodb::SchedulingParams_NetworkRequirements_NONE; + case SchedulingParams::NetworkRequirements::OPTIMISTIC: + return protodb::SchedulingParams_NetworkRequirements_OPTIMISTIC; + case SchedulingParams::NetworkRequirements::UNMETERED: + return protodb::SchedulingParams_NetworkRequirements_UNMETERED; + } + + NOTREACHED(); + return protodb::SchedulingParams_NetworkRequirements_NONE; +} + +SchedulingParams::BatteryRequirements +ProtoConversions::BatteryRequirementsFromProto( + protodb::SchedulingParams_BatteryRequirements battery_requirements) { + switch (battery_requirements) { + case protodb::SchedulingParams_BatteryRequirements_BATTERY_INSENSITIVE: + return SchedulingParams::BatteryRequirements::BATTERY_INSENSITIVE; + case protodb::SchedulingParams_BatteryRequirements_BATTERY_SENSITIVE: + return SchedulingParams::BatteryRequirements::BATTERY_SENSITIVE; + } + + NOTREACHED(); + return SchedulingParams::BatteryRequirements::BATTERY_INSENSITIVE; +} + +protodb::SchedulingParams_BatteryRequirements +ProtoConversions::BatteryRequirementsToProto( + SchedulingParams::BatteryRequirements battery_requirements) { + switch (battery_requirements) { + case SchedulingParams::BatteryRequirements::BATTERY_INSENSITIVE: + return protodb::SchedulingParams_BatteryRequirements_BATTERY_INSENSITIVE; + case SchedulingParams::BatteryRequirements::BATTERY_SENSITIVE: + return protodb::SchedulingParams_BatteryRequirements_BATTERY_SENSITIVE; + } + + NOTREACHED(); + return protodb::SchedulingParams_BatteryRequirements_BATTERY_INSENSITIVE; +} + +SchedulingParams::Priority ProtoConversions::SchedulingPriorityFromProto( + protodb::SchedulingParams_Priority priority) { + switch (priority) { + case protodb::SchedulingParams_Priority_LOW: + return SchedulingParams::Priority::LOW; + case protodb::SchedulingParams_Priority_NORMAL: + return SchedulingParams::Priority::NORMAL; + case protodb::SchedulingParams_Priority_HIGH: + return SchedulingParams::Priority::HIGH; + case protodb::SchedulingParams_Priority_UI: + return SchedulingParams::Priority::UI; + } + + NOTREACHED(); + return SchedulingParams::Priority::LOW; +} + +protodb::SchedulingParams_Priority ProtoConversions::SchedulingPriorityToProto( + SchedulingParams::Priority priority) { + switch (priority) { + case SchedulingParams::Priority::LOW: + return protodb::SchedulingParams_Priority_LOW; + case SchedulingParams::Priority::NORMAL: + return protodb::SchedulingParams_Priority_NORMAL; + case SchedulingParams::Priority::HIGH: + return protodb::SchedulingParams_Priority_HIGH; + case SchedulingParams::Priority::UI: + return protodb::SchedulingParams_Priority_UI; + } + + NOTREACHED(); + return protodb::SchedulingParams_Priority_LOW; +} + +SchedulingParams ProtoConversions::SchedulingParamsFromProto( + const protodb::SchedulingParams& proto) { + SchedulingParams scheduling_params; + + scheduling_params.cancel_time = + base::Time::FromInternalValue(proto.cancel_time()); + scheduling_params.priority = SchedulingPriorityFromProto(proto.priority()); + scheduling_params.network_requirements = + NetworkRequirementsFromProto(proto.network_requirements()); + scheduling_params.battery_requirements = + BatteryRequirementsFromProto(proto.battery_requirements()); + + return scheduling_params; +} + +void ProtoConversions::SchedulingParamsToProto( + const SchedulingParams& scheduling_params, + protodb::SchedulingParams* proto) { + proto->set_cancel_time(scheduling_params.cancel_time.ToInternalValue()); + proto->set_priority(SchedulingPriorityToProto(scheduling_params.priority)); + proto->set_network_requirements( + NetworkRequirementsToProto(scheduling_params.network_requirements)); + proto->set_battery_requirements( + BatteryRequirementsToProto(scheduling_params.battery_requirements)); +} + +RequestParams ProtoConversions::RequestParamsFromProto( + const protodb::RequestParams& proto) { + RequestParams request_params; + request_params.url = GURL(proto.url()); + request_params.method = proto.method(); + + for (int i = 0; i < proto.headers_size(); i++) { + protodb::RequestHeader header = proto.headers(i); + request_params.request_headers.SetHeader(header.key(), header.value()); + } + + return request_params; +} + +void ProtoConversions::RequestParamsToProto(const RequestParams& request_params, + protodb::RequestParams* proto) { + proto->set_url(request_params.url.spec()); + proto->set_method(request_params.method); + + int i = 0; + net::HttpRequestHeaders::Iterator iter(request_params.request_headers); + while (iter.GetNext()) { + protodb::RequestHeader* header = proto->add_headers(); + header->set_key(iter.name()); + header->set_value(iter.value()); + i++; + } +} + +Entry ProtoConversions::EntryFromProto(const protodb::Entry& proto) { + Entry entry; + + entry.guid = proto.guid(); + entry.client = DownloadClientFromProto(proto.name_space()); + entry.scheduling_params = + SchedulingParamsFromProto(proto.scheduling_params()); + entry.request_params = RequestParamsFromProto(proto.request_params()); + entry.state = RequestStateFromProto(proto.state()); + + return entry; +} + +protodb::Entry ProtoConversions::EntryToProto(const Entry& entry) { + protodb::Entry proto; + + proto.set_guid(entry.guid); + proto.set_name_space(DownloadClientToProto(entry.client)); + SchedulingParamsToProto(entry.scheduling_params, + proto.mutable_scheduling_params()); + RequestParamsToProto(entry.request_params, proto.mutable_request_params()); + proto.set_state(RequestStateToProto(entry.state)); + + return proto; +} + +std::unique_ptr<std::vector<Entry>> ProtoConversions::EntryVectorFromProto( + std::unique_ptr<std::vector<protodb::Entry>> protos) { + auto entries = base::MakeUnique<std::vector<Entry>>(); + for (auto& proto : *protos) { + entries->push_back(EntryFromProto(proto)); + } + + return entries; +} + +std::unique_ptr<std::vector<protodb::Entry>> +ProtoConversions::EntryVectorToProto( + std::unique_ptr<std::vector<Entry>> entries) { + auto protos = base::MakeUnique<std::vector<protodb::Entry>>(); + for (auto& entry : *entries) { + protos->push_back(EntryToProto(entry)); + } + + return protos; +} + +} // namespace download
diff --git a/components/download/internal/proto_conversions.h b/components/download/internal/proto_conversions.h new file mode 100644 index 0000000..4d2e4e5 --- /dev/null +++ b/components/download/internal/proto_conversions.h
@@ -0,0 +1,64 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_DOWNLOAD_INTERNAL_PROTO_CONVERSIONS_H_ +#define COMPONENTS_DOWNLOAD_INTERNAL_PROTO_CONVERSIONS_H_ + +#include "components/download/internal/entry.h" +#include "components/download/internal/proto/entry.pb.h" +#include "components/download/internal/proto/request.pb.h" +#include "components/download/internal/proto/scheduling.pb.h" + +namespace download { + +class ProtoConversions { + public: + static Entry EntryFromProto(const protodb::Entry& proto); + + static protodb::Entry EntryToProto(const Entry& entry); + + static std::unique_ptr<std::vector<Entry>> EntryVectorFromProto( + std::unique_ptr<std::vector<protodb::Entry>> proto); + + static std::unique_ptr<std::vector<protodb::Entry>> EntryVectorToProto( + std::unique_ptr<std::vector<Entry>> entries); + + protected: + static protodb::Entry_State RequestStateToProto(Entry::State state); + static Entry::State RequestStateFromProto(protodb::Entry_State state); + + static protodb::DownloadClient DownloadClientToProto(DownloadClient client); + static DownloadClient DownloadClientFromProto(protodb::DownloadClient client); + + static SchedulingParams::NetworkRequirements NetworkRequirementsFromProto( + protodb::SchedulingParams_NetworkRequirements network_requirements); + static protodb::SchedulingParams_NetworkRequirements + NetworkRequirementsToProto( + SchedulingParams::NetworkRequirements network_requirements); + + static SchedulingParams::BatteryRequirements BatteryRequirementsFromProto( + protodb::SchedulingParams_BatteryRequirements battery_requirements); + static protodb::SchedulingParams_BatteryRequirements + BatteryRequirementsToProto( + SchedulingParams::BatteryRequirements battery_requirements); + + static SchedulingParams::Priority SchedulingPriorityFromProto( + protodb::SchedulingParams_Priority priority); + static protodb::SchedulingParams_Priority SchedulingPriorityToProto( + SchedulingParams::Priority priority); + + static SchedulingParams SchedulingParamsFromProto( + const protodb::SchedulingParams& proto); + static void SchedulingParamsToProto(const SchedulingParams& scheduling_params, + protodb::SchedulingParams* proto); + + static RequestParams RequestParamsFromProto( + const protodb::RequestParams& proto); + static void RequestParamsToProto(const RequestParams& request_params, + protodb::RequestParams* proto); +}; + +} // namespace download + +#endif // COMPONENTS_DOWNLOAD_INTERNAL_PROTO_CONVERSIONS_H_
diff --git a/components/download/internal/proto_conversions_unittest.cc b/components/download/internal/proto_conversions_unittest.cc new file mode 100644 index 0000000..04198c5 --- /dev/null +++ b/components/download/internal/proto_conversions_unittest.cc
@@ -0,0 +1,152 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <utility> + +#include "base/guid.h" +#include "base/memory/ptr_util.h" +#include "components/download/internal/entry.h" +#include "components/download/internal/proto_conversions.h" +#include "components/download/internal/test/entry_utils.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { +std::string TEST_URL = "https://google.com"; + +} // namespace + +namespace download { + +class ProtoConversionsTest : public testing::Test, public ProtoConversions { + public: + ~ProtoConversionsTest() override {} +}; + +TEST_F(ProtoConversionsTest, StateConversion) { + Entry::State states[] = {Entry::State::NEW, Entry::State::AVAILABLE, + Entry::State::ACTIVE, Entry::State::PAUSED, + Entry::State::COMPLETE, Entry::State::WATCHDOG}; + for (auto state : states) { + ASSERT_EQ(state, RequestStateFromProto(RequestStateToProto(state))); + } +} + +TEST_F(ProtoConversionsTest, DownloadClientConversion) { + DownloadClient clients[] = {DownloadClient::INVALID, DownloadClient::TEST, + DownloadClient::OFFLINE_PAGE_PREFETCH, + DownloadClient::BOUNDARY}; + for (auto client : clients) { + ASSERT_EQ(client, DownloadClientFromProto(DownloadClientToProto(client))); + } +} + +TEST_F(ProtoConversionsTest, NetworkRequirementsConversion) { + SchedulingParams::NetworkRequirements values[] = { + SchedulingParams::NetworkRequirements::NONE, + SchedulingParams::NetworkRequirements::OPTIMISTIC, + SchedulingParams::NetworkRequirements::UNMETERED}; + for (auto value : values) { + ASSERT_EQ(value, + NetworkRequirementsFromProto(NetworkRequirementsToProto(value))); + } +} + +TEST_F(ProtoConversionsTest, BatteryRequirementsConversion) { + SchedulingParams::BatteryRequirements values[] = { + SchedulingParams::BatteryRequirements::BATTERY_INSENSITIVE, + SchedulingParams::BatteryRequirements::BATTERY_SENSITIVE}; + for (auto value : values) { + ASSERT_EQ(value, + BatteryRequirementsFromProto(BatteryRequirementsToProto(value))); + } +} + +TEST_F(ProtoConversionsTest, SchedulingPriorityConversion) { + SchedulingParams::Priority values[] = { + SchedulingParams::Priority::LOW, SchedulingParams::Priority::NORMAL, + SchedulingParams::Priority::HIGH, SchedulingParams::Priority::UI, + SchedulingParams::Priority::DEFAULT}; + for (auto value : values) { + ASSERT_EQ(value, + SchedulingPriorityFromProto(SchedulingPriorityToProto(value))); + } +} + +TEST_F(ProtoConversionsTest, SchedulingParamsConversion) { + SchedulingParams expected; + expected.cancel_time = base::Time::Now(); + expected.priority = SchedulingParams::Priority::DEFAULT; + expected.network_requirements = + SchedulingParams::NetworkRequirements::OPTIMISTIC; + expected.battery_requirements = + SchedulingParams::BatteryRequirements::BATTERY_SENSITIVE; + + protodb::SchedulingParams proto; + SchedulingParamsToProto(expected, &proto); + SchedulingParams actual = SchedulingParamsFromProto(proto); + EXPECT_EQ(expected.cancel_time, actual.cancel_time); + EXPECT_EQ(SchedulingParams::Priority::DEFAULT, actual.priority); + EXPECT_EQ(SchedulingParams::NetworkRequirements::OPTIMISTIC, + actual.network_requirements); + EXPECT_EQ(SchedulingParams::BatteryRequirements::BATTERY_SENSITIVE, + actual.battery_requirements); +} + +TEST_F(ProtoConversionsTest, RequestParamsWithHeadersConversion) { + RequestParams expected; + expected.url = GURL(TEST_URL); + expected.method = "GET"; + expected.request_headers.SetHeader("key1", "value1"); + expected.request_headers.SetHeader("key2", "value2"); + + protodb::RequestParams proto; + RequestParamsToProto(expected, &proto); + RequestParams actual = RequestParamsFromProto(proto); + + EXPECT_EQ(expected.url, actual.url); + EXPECT_EQ(expected.method, actual.method); + + std::string out; + actual.request_headers.GetHeader("key1", &out); + EXPECT_EQ("value1", out); + actual.request_headers.GetHeader("key2", &out); + EXPECT_EQ("value2", out); + EXPECT_EQ(expected.request_headers.ToString(), + actual.request_headers.ToString()); +} + +TEST_F(ProtoConversionsTest, EntryConversion) { + Entry expected = test::BuildEntry(DownloadClient::TEST, base::GenerateGUID()); + Entry actual = EntryFromProto(EntryToProto(expected)); + EXPECT_TRUE(test::CompareEntry(&expected, &actual)); + + expected = test::BuildEntry( + DownloadClient::TEST, base::GenerateGUID(), base::Time::Now(), + SchedulingParams::NetworkRequirements::OPTIMISTIC, + SchedulingParams::BatteryRequirements::BATTERY_SENSITIVE, + SchedulingParams::Priority::HIGH, GURL(TEST_URL), "GET", + Entry::State::ACTIVE); + actual = EntryFromProto(EntryToProto(expected)); + EXPECT_TRUE(test::CompareEntry(&expected, &actual)); +} + +TEST_F(ProtoConversionsTest, EntryVectorConversion) { + std::vector<Entry> expected; + expected.push_back( + test::BuildEntry(DownloadClient::TEST, base::GenerateGUID())); + expected.push_back(test::BuildEntry(DownloadClient::OFFLINE_PAGE_PREFETCH, + base::GenerateGUID())); + expected.push_back(test::BuildEntry( + DownloadClient::TEST, base::GenerateGUID(), base::Time::Now(), + SchedulingParams::NetworkRequirements::OPTIMISTIC, + SchedulingParams::BatteryRequirements::BATTERY_SENSITIVE, + SchedulingParams::Priority::HIGH, GURL(TEST_URL), "GET", + Entry::State::ACTIVE)); + + auto actual = EntryVectorFromProto( + EntryVectorToProto(base::MakeUnique<std::vector<Entry>>(expected))); + EXPECT_TRUE(test::CompareEntryList(expected, *actual)); +} + +} // namespace download
diff --git a/components/download/internal/store.h b/components/download/internal/store.h index 04a39bf..4622b26a 100644 --- a/components/download/internal/store.h +++ b/components/download/internal/store.h
@@ -10,8 +10,6 @@ #include <vector> #include "base/callback_forward.h" -#include "base/memory/ref_counted.h" -#include "base/sequenced_task_runner.h" namespace download { @@ -36,10 +34,6 @@ // Store. virtual void Initialize(InitCallback callback) = 0; - // Destroyes the store and asynchronously returns whether or not that - // destruction was successful. - virtual void Destroy(StoreCallback callback) = 0; - // Adds or updates |entry| in this Store asynchronously and returns whether or // not that was successful. virtual void Update(const Entry& entry, StoreCallback callback) = 0;
diff --git a/components/download/internal/test/BUILD.gn b/components/download/internal/test/BUILD.gn index 87032dc..3ee693e 100644 --- a/components/download/internal/test/BUILD.gn +++ b/components/download/internal/test/BUILD.gn
@@ -12,6 +12,8 @@ "entry_utils.h", "mock_model_client.cc", "mock_model_client.h", + "noop_store.cc", + "noop_store.h", "test_download_driver.cc", "test_download_driver.h", "test_store.cc",
diff --git a/components/download/internal/test/entry_utils.cc b/components/download/internal/test/entry_utils.cc index 33b4abf..b3b8e850 100644 --- a/components/download/internal/test/entry_utils.cc +++ b/components/download/internal/test/entry_utils.cc
@@ -9,19 +9,41 @@ namespace download { namespace test { -bool SuperficialEntryCompare(const Entry* const& expected, - const Entry* const& actual) { +bool CompareEntry(const Entry* const& expected, const Entry* const& actual) { if (expected == nullptr || actual == nullptr) return expected == actual; + // TODO(shaktisahu): Add operator== in Entry. return expected->client == actual->client && expected->guid == actual->guid && + expected->scheduling_params.cancel_time == + actual->scheduling_params.cancel_time && + expected->scheduling_params.network_requirements == + actual->scheduling_params.network_requirements && + expected->scheduling_params.battery_requirements == + actual->scheduling_params.battery_requirements && + expected->scheduling_params.priority == + actual->scheduling_params.priority && + expected->request_params.url == actual->request_params.url && + expected->request_params.method == actual->request_params.method && + expected->request_params.request_headers.ToString() == + actual->request_params.request_headers.ToString() && expected->state == actual->state; } -bool SuperficialEntryListCompare(const std::vector<Entry*>& expected, - const std::vector<Entry*>& actual) { +bool CompareEntryList(const std::vector<Entry*>& expected, + const std::vector<Entry*>& actual) { return std::is_permutation(actual.cbegin(), actual.cend(), expected.cbegin(), - SuperficialEntryCompare); + CompareEntry); +} + +bool EntryComparison(const Entry& expected, const Entry& actual) { + return CompareEntry(&expected, &actual); +} + +bool CompareEntryList(const std::vector<Entry>& list1, + const std::vector<Entry>& list2) { + return std::is_permutation(list1.begin(), list1.end(), list2.begin(), + EntryComparison); } Entry BuildEntry(DownloadClient client, const std::string& guid) { @@ -31,5 +53,25 @@ return entry; } +Entry BuildEntry(DownloadClient client, + const std::string& guid, + base::Time cancel_time, + SchedulingParams::NetworkRequirements network_requirements, + SchedulingParams::BatteryRequirements battery_requirements, + SchedulingParams::Priority priority, + const GURL& url, + const std::string& request_method, + Entry::State state) { + Entry entry = BuildEntry(client, guid); + entry.scheduling_params.cancel_time = cancel_time; + entry.scheduling_params.network_requirements = network_requirements; + entry.scheduling_params.battery_requirements = battery_requirements; + entry.scheduling_params.priority = priority; + entry.request_params.url = url; + entry.request_params.method = request_method; + entry.state = state; + return entry; +} + } // namespace test } // namespace download
diff --git a/components/download/internal/test/entry_utils.h b/components/download/internal/test/entry_utils.h index 2a7b422..54144be6 100644 --- a/components/download/internal/test/entry_utils.h +++ b/components/download/internal/test/entry_utils.h
@@ -13,14 +13,26 @@ namespace download { namespace test { -bool SuperficialEntryCompare(const Entry* const& expected, - const Entry* const& actual); +bool CompareEntry(const Entry* const& expected, const Entry* const& actual); -bool SuperficialEntryListCompare(const std::vector<Entry*>& a, - const std::vector<Entry*>& b); +bool CompareEntryList(const std::vector<Entry*>& a, + const std::vector<Entry*>& b); + +bool CompareEntryList(const std::vector<Entry>& list1, + const std::vector<Entry>& list2); Entry BuildEntry(DownloadClient client, const std::string& guid); +Entry BuildEntry(DownloadClient client, + const std::string& guid, + base::Time cancel_time, + SchedulingParams::NetworkRequirements network_requirements, + SchedulingParams::BatteryRequirements battery_requirements, + SchedulingParams::Priority priority, + const GURL& url, + const std::string& request_method, + Entry::State state); + } // namespace test } // namespace download
diff --git a/components/download/internal/test/mock_model_client.h b/components/download/internal/test/mock_model_client.h index 2b82f0c..cd9a7f8 100644 --- a/components/download/internal/test/mock_model_client.h +++ b/components/download/internal/test/mock_model_client.h
@@ -20,7 +20,6 @@ // Model::Client implementation. MOCK_METHOD1(OnInitialized, void(bool)); - MOCK_METHOD1(OnDestroyed, void(bool)); MOCK_METHOD3(OnItemAdded, void(bool, DownloadClient, const std::string&)); MOCK_METHOD3(OnItemUpdated, void(bool, DownloadClient, const std::string&)); MOCK_METHOD3(OnItemRemoved, void(bool, DownloadClient, const std::string&));
diff --git a/components/download/internal/noop_store.cc b/components/download/internal/test/noop_store.cc similarity index 85% rename from components/download/internal/noop_store.cc rename to components/download/internal/test/noop_store.cc index 42785cb..59931bb6 100644 --- a/components/download/internal/noop_store.cc +++ b/components/download/internal/test/noop_store.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/download/internal/noop_store.h" +#include "components/download/internal/test/noop_store.h" #include "base/bind.h" #include "base/threading/thread_task_runner_handle.h" @@ -27,11 +27,6 @@ std::move(callback))); } -void NoopStore::Destroy(StoreCallback callback) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), true /** success */)); -} - void NoopStore::Update(const Entry& entry, StoreCallback callback) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(std::move(callback), true /** success */));
diff --git a/components/download/internal/noop_store.h b/components/download/internal/test/noop_store.h similarity index 84% rename from components/download/internal/noop_store.h rename to components/download/internal/test/noop_store.h index 4bad9ed..edc03d70 100644 --- a/components/download/internal/noop_store.h +++ b/components/download/internal/test/noop_store.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_DOWNLOAD_INTERNAL_NOOP_STORE_H_ -#define COMPONENTS_DOWNLOAD_INTERNAL_NOOP_STORE_H_ +#ifndef COMPONENTS_DOWNLOAD_INTERNAL_TEST_NOOP_STORE_H_ +#define COMPONENTS_DOWNLOAD_INTERNAL_TEST_NOOP_STORE_H_ #include "base/macros.h" #include "base/memory/weak_ptr.h" @@ -25,7 +25,6 @@ // Store implementation. bool IsInitialized() override; void Initialize(InitCallback callback) override; - void Destroy(StoreCallback callback) override; void Update(const Entry& entry, StoreCallback callback) override; void Remove(const std::string& guid, StoreCallback callback) override; @@ -43,4 +42,4 @@ } // namespace download -#endif // COMPONENTS_DOWNLOAD_INTERNAL_NOOP_STORE_H_ +#endif // COMPONENTS_DOWNLOAD_INTERNAL_TEST_NOOP_STORE_H_
diff --git a/components/download/internal/test/test_store.cc b/components/download/internal/test/test_store.cc index 01faec7..c9e472b94 100644 --- a/components/download/internal/test/test_store.cc +++ b/components/download/internal/test/test_store.cc
@@ -9,8 +9,7 @@ namespace download { namespace test { -TestStore::TestStore() - : ready_(false), init_called_(false), destroy_called_(false) {} +TestStore::TestStore() : ready_(false), init_called_(false) {} TestStore::~TestStore() {} @@ -23,11 +22,6 @@ init_callback_ = std::move(callback); } -void TestStore::Destroy(StoreCallback callback) { - destroy_called_ = true; - destroy_callback_ = std::move(callback); -} - void TestStore::Update(const Entry& entry, StoreCallback callback) { updated_entries_.push_back(entry); update_callback_ = std::move(callback); @@ -46,11 +40,6 @@ std::move(init_callback_).Run(success, std::move(entries)); } -void TestStore::TriggerDestroy(bool success) { - DCHECK(destroy_callback_); - std::move(destroy_callback_).Run(success); -} - void TestStore::TriggerUpdate(bool success) { DCHECK(update_callback_); std::move(update_callback_).Run(success);
diff --git a/components/download/internal/test/test_store.h b/components/download/internal/test/test_store.h index e64d8ba..2cb5f57 100644 --- a/components/download/internal/test/test_store.h +++ b/components/download/internal/test/test_store.h
@@ -8,6 +8,7 @@ #include <string> #include <vector> +#include "base/callback.h" #include "base/macros.h" #include "components/download/internal/store.h" @@ -25,13 +26,11 @@ // Store implementation. bool IsInitialized() override; void Initialize(InitCallback callback) override; - void Destroy(StoreCallback callback) override; void Update(const Entry& entry, StoreCallback callback) override; void Remove(const std::string& guid, StoreCallback callback) override; // Callback trigger methods. void TriggerInit(bool success, std::unique_ptr<std::vector<Entry>> entries); - void TriggerDestroy(bool success); void TriggerUpdate(bool success); void TriggerRemove(bool success); @@ -39,7 +38,6 @@ const Entry* LastUpdatedEntry() const; std::string LastRemovedEntry() const; bool init_called() const { return init_called_; } - bool destroy_called() const { return destroy_called_; } const std::vector<Entry>& updated_entries() const { return updated_entries_; } const std::vector<std::string>& removed_entries() const { return removed_entries_; @@ -49,13 +47,11 @@ bool ready_; bool init_called_; - bool destroy_called_; std::vector<Entry> updated_entries_; std::vector<std::string> removed_entries_; InitCallback init_callback_; - StoreCallback destroy_callback_; StoreCallback update_callback_; StoreCallback remove_callback_;
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc index 998769b..955dc0a1 100644 --- a/components/exo/shell_surface.cc +++ b/components/exo/shell_surface.cc
@@ -108,17 +108,23 @@ if (component != HTNOWHERE && component != HTCLIENT) return true; - // If there is an underlay, test against it's bounds instead since it will - // be equal or larger than the surface's bounds. + // If there is an underlay, test against it first as it's bounds may be + // larger than the surface's bounds. aura::Window* shadow_underlay = static_cast<ShellSurface*>( widget_->widget_delegate()->GetContentsView()) ->shadow_underlay(); if (shadow_underlay) { - aura::Window::ConvertPointToTarget(window, shadow_underlay, &local_point); - return gfx::Rect(shadow_underlay->layer()->size()).Contains(local_point); + gfx::Point local_point_in_shadow_underlay = local_point; + aura::Window::ConvertPointToTarget(window, shadow_underlay, + &local_point_in_shadow_underlay); + if (gfx::Rect(shadow_underlay->layer()->size()) + .Contains(local_point_in_shadow_underlay)) { + return true; + } } + // Otherwise, fallback to hit test on the surface. aura::Window::ConvertPointToTarget(window, surface->window(), &local_point); return surface->HitTestRect(gfx::Rect(local_point, gfx::Size(1, 1))); } @@ -128,7 +134,8 @@ aura::Window* window = static_cast<aura::Window*>(root); Surface* surface = ShellSurface::GetMainSurface(window); - // Send events which are outside of the surface's bounds to the underlay. + // Send events which wouldn't be handled by the surface, to the shadow + // underlay. aura::Window* shadow_underlay = static_cast<ShellSurface*>( widget_->widget_delegate()->GetContentsView()) @@ -136,8 +143,12 @@ if (surface && event->IsLocatedEvent() && shadow_underlay) { gfx::Point local_point = event->AsLocatedEvent()->location(); int component = widget_->non_client_view()->NonClientHitTest(local_point); - if (component == HTNOWHERE) - return shadow_underlay; + if (component == HTNOWHERE) { + aura::Window::ConvertPointToTarget(window, surface->window(), + &local_point); + if (!surface->HitTestRect(gfx::Rect(local_point, gfx::Size(1, 1)))) + return shadow_underlay; + } } return aura::WindowTargeter::FindTargetForEvent(root, event); }
diff --git a/components/feature_engagement_tracker/internal/availability_store.cc b/components/feature_engagement_tracker/internal/availability_store.cc index 3c0163c8..8877818 100644 --- a/components/feature_engagement_tracker/internal/availability_store.cc +++ b/components/feature_engagement_tracker/internal/availability_store.cc
@@ -107,10 +107,11 @@ } // Write all changes to the DB. - db->UpdateEntries(std::move(additions), std::move(deletes), - base::BindOnce(&OnDBUpdateComplete, std::move(db), - std::move(on_loaded_callback), - std::move(feature_availabilities))); + auto* db_ptr = db.get(); + db_ptr->UpdateEntries(std::move(additions), std::move(deletes), + base::BindOnce(&OnDBUpdateComplete, std::move(db), + std::move(on_loaded_callback), + std::move(feature_availabilities))); } void OnDBInitComplete( @@ -128,9 +129,10 @@ return; } - db->LoadEntries(base::BindOnce(&OnDBLoadComplete, std::move(db), - std::move(feature_filter), - std::move(on_loaded_callback), current_day)); + auto* db_ptr = db.get(); + db_ptr->LoadEntries(base::BindOnce( + &OnDBLoadComplete, std::move(db), std::move(feature_filter), + std::move(on_loaded_callback), current_day)); } } // namespace @@ -142,10 +144,11 @@ FeatureVector feature_filter, AvailabilityStore::OnLoadedCallback on_loaded_callback, uint32_t current_day) { - db->Init(kDatabaseUMAName, storage_dir, - base::BindOnce(&OnDBInitComplete, std::move(db), - std::move(feature_filter), - std::move(on_loaded_callback), current_day)); + auto* db_ptr = db.get(); + db_ptr->Init(kDatabaseUMAName, storage_dir, + base::BindOnce(&OnDBInitComplete, std::move(db), + std::move(feature_filter), + std::move(on_loaded_callback), current_day)); } } // namespace feature_engagement_tracker
diff --git a/components/feature_engagement_tracker/internal/system_time_provider_unittest.cc b/components/feature_engagement_tracker/internal/system_time_provider_unittest.cc index c252b63..6bcf53c 100644 --- a/components/feature_engagement_tracker/internal/system_time_provider_unittest.cc +++ b/components/feature_engagement_tracker/internal/system_time_provider_unittest.cc
@@ -23,7 +23,7 @@ exploded_time.millisecond = 0; base::Time out_time; - EXPECT_TRUE(base::Time::FromLocalExploded(exploded_time, &out_time)); + EXPECT_TRUE(base::Time::FromUTCExploded(exploded_time, &out_time)); return out_time; }
diff --git a/components/ntp_snippets/content_suggestions_service.h b/components/ntp_snippets/content_suggestions_service.h index 40c442b..ddeae6e3e 100644 --- a/components/ntp_snippets/content_suggestions_service.h +++ b/components/ntp_snippets/content_suggestions_service.h
@@ -15,7 +15,6 @@ #include "base/observer_list.h" #include "base/optional.h" #include "base/scoped_observer.h" -#include "base/supports_user_data.h" #include "base/task/cancelable_task_tracker.h" #include "base/time/time.h" #include "components/history/core/browser/history_service.h" @@ -48,7 +47,6 @@ // Retrieves suggestions from a number of ContentSuggestionsProviders and serves // them grouped into categories. There can be at most one provider per category. class ContentSuggestionsService : public KeyedService, - public base::SupportsUserData, public ContentSuggestionsProvider::Observer, public SigninManagerBase::Observer, public history::HistoryServiceObserver {
diff --git a/components/offline_pages/content/BUILD.gn b/components/offline_pages/content/BUILD.gn deleted file mode 100644 index 5b1ddb5..0000000 --- a/components/offline_pages/content/BUILD.gn +++ /dev/null
@@ -1,45 +0,0 @@ -# Copyright 2015 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -if (is_android) { - import("//build/config/android/rules.gni") -} - -static_library("content") { - sources = [ - "prefetch_service_factory.cc", - "prefetch_service_factory.h", - "suggested_articles_observer.cc", - "suggested_articles_observer.h", - ] - - deps = [ - "//base", - "//components/keyed_service/content", - "//components/ntp_snippets", - "//components/offline_pages/core", - "//components/offline_pages/core:switches", - "//components/offline_pages/core/prefetch", - "//content/public/browser", - ] -} - -source_set("unit_tests") { - testonly = true - sources = [ - "suggested_articles_observer_unittest.cc", - ] - - deps = [ - ":content", - "//base", - "//base/test:test_support", - "//components/offline_pages/core", - "//components/offline_pages/core:test_support", - "//components/offline_pages/core/prefetch", - "//content/test:test_support", - "//testing/gtest", - "//url", - ] -}
diff --git a/components/offline_pages/content/DEPS b/components/offline_pages/content/DEPS deleted file mode 100644 index 4edd3b1..0000000 --- a/components/offline_pages/content/DEPS +++ /dev/null
@@ -1,6 +0,0 @@ -include_rules = [ - "+components/keyed_service/content", - "+components/ntp_snippets", - "+content/public/browser", - "+content/public/test", -]
diff --git a/components/offline_pages/content/suggested_articles_observer.cc b/components/offline_pages/content/suggested_articles_observer.cc deleted file mode 100644 index 4b60a28..0000000 --- a/components/offline_pages/content/suggested_articles_observer.cc +++ /dev/null
@@ -1,170 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/offline_pages/content/suggested_articles_observer.h" - -#include <unordered_set> - -#include "base/memory/ptr_util.h" -#include "components/ntp_snippets/category.h" -#include "components/ntp_snippets/category_status.h" -#include "components/offline_pages/content/prefetch_service_factory.h" -#include "components/offline_pages/core/client_namespace_constants.h" -#include "components/offline_pages/core/offline_page_feature.h" -#include "components/offline_pages/core/prefetch/prefetch_dispatcher.h" -#include "components/offline_pages/core/prefetch/prefetch_service.h" - -using ntp_snippets::Category; -using ntp_snippets::ContentSuggestion; - -namespace offline_pages { - -namespace { - -int kOfflinePageSuggestedArticlesObserverUserDataKey; - -const ntp_snippets::Category& ArticlesCategory() { - static ntp_snippets::Category articles = - Category::FromKnownCategory(ntp_snippets::KnownCategories::ARTICLES); - return articles; -} - -ClientId CreateClientIDFromSuggestionId(const ContentSuggestion::ID& id) { - return ClientId(kSuggestedArticlesNamespace, id.id_within_category()); -} - -// The default delegate that contains external dependencies for the Offline Page -// Suggestions Observer. This is unused in tests, which implement their own -// Delegate. -class DefaultDelegate : public SuggestedArticlesObserver::Delegate { - public: - explicit DefaultDelegate(ntp_snippets::ContentSuggestionsService* service); - ~DefaultDelegate() override = default; - - const std::vector<ContentSuggestion>& GetSuggestions( - const Category& category) override; - PrefetchService* GetPrefetchService( - content::BrowserContext* context) override; - - private: - ntp_snippets::ContentSuggestionsService* service_; -}; - -DefaultDelegate::DefaultDelegate( - ntp_snippets::ContentSuggestionsService* service) - : service_(service) {} - -const std::vector<ContentSuggestion>& DefaultDelegate::GetSuggestions( - const Category& category) { - return service_->GetSuggestionsForCategory(category); -} - -PrefetchService* DefaultDelegate::GetPrefetchService( - content::BrowserContext* context) { - return PrefetchServiceFactory::GetForBrowserContext(context); -} - -} // namespace - -// static -void SuggestedArticlesObserver::ObserveContentSuggestionsService( - content::BrowserContext* browser_context, - ntp_snippets::ContentSuggestionsService* service) { - if (!offline_pages::IsPrefetchingOfflinePagesEnabled()) - return; - - auto suggestions_observer = base::MakeUnique<SuggestedArticlesObserver>( - browser_context, base::MakeUnique<DefaultDelegate>(service)); - service->AddObserver(suggestions_observer.get()); - service->SetUserData(&kOfflinePageSuggestedArticlesObserverUserDataKey, - std::move(suggestions_observer)); -} - -SuggestedArticlesObserver::SuggestedArticlesObserver( - content::BrowserContext* browser_context, - std::unique_ptr<Delegate> delegate) - : browser_context_(browser_context), delegate_(std::move(delegate)) {} - -SuggestedArticlesObserver::~SuggestedArticlesObserver() = default; - -void SuggestedArticlesObserver::OnNewSuggestions(Category category) { - // TODO(dewittj): Change this to check whether a given category is not - // a _remote_ category. - if (category != ArticlesCategory() || - category_status_ != ntp_snippets::CategoryStatus::AVAILABLE) { - return; - } - - const std::vector<ContentSuggestion>& suggestions = - delegate_->GetSuggestions(ArticlesCategory()); - if (suggestions.empty()) - return; - - std::vector<PrefetchDispatcher::PrefetchURL> prefetch_urls; - for (const ContentSuggestion& suggestion : suggestions) { - prefetch_urls.push_back( - {CreateClientIDFromSuggestionId(suggestion.id()), suggestion.url()}); - } - - PrefetchService* service = delegate_->GetPrefetchService(browser_context_); - if (service == nullptr) { - DVLOG(1) << "PrefetchService unavailable to the " - "SuggestedArticlesObserver."; - return; - } - service->GetDispatcher()->AddCandidatePrefetchURLs(prefetch_urls); -} - -void SuggestedArticlesObserver::OnCategoryStatusChanged( - Category category, - ntp_snippets::CategoryStatus new_status) { - if (category != ArticlesCategory() || category_status_ == new_status) - return; - - category_status_ = new_status; - - if (category_status_ == - ntp_snippets::CategoryStatus::CATEGORY_EXPLICITLY_DISABLED || - category_status_ == - ntp_snippets::CategoryStatus::ALL_SUGGESTIONS_EXPLICITLY_DISABLED) { - PrefetchService* service = delegate_->GetPrefetchService(browser_context_); - if (service == nullptr) { - DVLOG(1) << "PrefetchService unavailable to the " - "SuggestedArticlesObserver."; - return; - } - service->GetDispatcher()->RemoveAllUnprocessedPrefetchURLs( - kSuggestedArticlesNamespace); - } -} - -void SuggestedArticlesObserver::OnSuggestionInvalidated( - const ContentSuggestion::ID& suggestion_id) { - PrefetchService* service = delegate_->GetPrefetchService(browser_context_); - if (service == nullptr) { - DVLOG(1) << "PrefetchService unavailable to the " - "SuggestedArticlesObserver."; - return; - } - service->GetDispatcher()->RemovePrefetchURLsByClientId( - CreateClientIDFromSuggestionId(suggestion_id)); -} - -void SuggestedArticlesObserver::OnFullRefreshRequired() { - PrefetchService* service = delegate_->GetPrefetchService(browser_context_); - if (service == nullptr) { - DVLOG(1) << "PrefetchService unavailable to the " - "SuggestedArticlesObserver."; - return; - } - service->GetDispatcher()->RemoveAllUnprocessedPrefetchURLs( - kSuggestedArticlesNamespace); - OnNewSuggestions(ArticlesCategory()); -} - -void SuggestedArticlesObserver::ContentSuggestionsServiceShutdown() { - // No need to do anything here, we will just stop getting events. -} - -} // namespace offline_pages
diff --git a/components/offline_pages/content/suggested_articles_observer.h b/components/offline_pages/content/suggested_articles_observer.h deleted file mode 100644 index 6448c01..0000000 --- a/components/offline_pages/content/suggested_articles_observer.h +++ /dev/null
@@ -1,80 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_OFFLINE_PAGES_CONTENT_SUGGESTED_ARTICLES_OBSERVER_H_ -#define COMPONENTS_OFFLINE_PAGES_CONTENT_SUGGESTED_ARTICLES_OBSERVER_H_ - -#include <memory> - -#include "base/callback.h" -#include "base/memory/weak_ptr.h" -#include "components/ntp_snippets/content_suggestions_service.h" - -namespace content { -class BrowserContext; -} // namespace content - -namespace ntp_snippets { -class Category; -} - -namespace offline_pages { -class PrefetchService; - -// Observes the ContentSuggestionsService, listening for new suggestions in the -// ARTICLES category. When those suggestions arrive, it then forwards them to -// the Prefetch Service, which does not know about Content Suggestions -// specifically. -class SuggestedArticlesObserver - : public ntp_snippets::ContentSuggestionsService::Observer, - public base::SupportsUserData::Data { - public: - // Delegate exists to allow for dependency injection in unit tests. - // SuggestedArticlesObserver implements its own delegate, |DefaultDelegate| in - // the .cc file that forwards to the ContentSuggestionsService and the - // PrefetchServiceFactory. Code inside |DefaultDelegate| should be as simple - // as possible, since it will only be covered by instrumentation/browser - // tests. - class Delegate { - public: - virtual const std::vector<ntp_snippets::ContentSuggestion>& GetSuggestions( - const ntp_snippets::Category& category) = 0; - virtual PrefetchService* GetPrefetchService( - content::BrowserContext* context) = 0; - virtual ~Delegate() = default; - }; - - // This API creates a new SuggestedArticlesObserver and adds it as an - // observer to the ContentSuggestionsService provided. Its lifetime is - // managed by the ContentSuggestionsService. - static void ObserveContentSuggestionsService( - content::BrowserContext* browser_context, - ntp_snippets::ContentSuggestionsService* service); - - SuggestedArticlesObserver(content::BrowserContext* browser_context, - std::unique_ptr<Delegate> delegate); - ~SuggestedArticlesObserver() override; - - // ContentSuggestionsService::Observer overrides. - void OnNewSuggestions(ntp_snippets::Category category) override; - void OnCategoryStatusChanged( - ntp_snippets::Category category, - ntp_snippets::CategoryStatus new_status) override; - void OnSuggestionInvalidated( - const ntp_snippets::ContentSuggestion::ID& suggestion_id) override; - void OnFullRefreshRequired() override; - void ContentSuggestionsServiceShutdown() override; - - private: - content::BrowserContext* browser_context_; - ntp_snippets::CategoryStatus category_status_ = - ntp_snippets::CategoryStatus::INITIALIZING; - std::unique_ptr<Delegate> delegate_; - - DISALLOW_COPY_AND_ASSIGN(SuggestedArticlesObserver); -}; - -} // namespace offline_pages - -#endif // COMPONENTS_OFFLINE_PAGES_CONTENT_SUGGESTED_ARTICLES_OBSERVER_H_
diff --git a/components/offline_pages/core/DEPS b/components/offline_pages/core/DEPS index a232688..5ef8eb9f 100644 --- a/components/offline_pages/core/DEPS +++ b/components/offline_pages/core/DEPS
@@ -1,5 +1,7 @@ include_rules = [ "+components/keyed_service", + "+components/gcm_driver", + "+components/ntp_snippets", "+components/version_info", "+net", "+sql",
diff --git a/components/offline_pages/core/prefetch/BUILD.gn b/components/offline_pages/core/prefetch/BUILD.gn index ae365d2b..58ca40a7 100644 --- a/components/offline_pages/core/prefetch/BUILD.gn +++ b/components/offline_pages/core/prefetch/BUILD.gn
@@ -16,6 +16,9 @@ "prefetch_dispatcher.h", "prefetch_dispatcher_impl.cc", "prefetch_dispatcher_impl.h", + "prefetch_gcm_app_handler.cc", + "prefetch_gcm_app_handler.h", + "prefetch_gcm_handler.h", "prefetch_item.cc", "prefetch_item.h", "prefetch_proto_utils.cc", @@ -27,6 +30,8 @@ "prefetch_service_impl.h", "prefetch_types.cc", "prefetch_types.h", + "suggested_articles_observer.cc", + "suggested_articles_observer.h", ] public_deps = [ @@ -34,8 +39,12 @@ ] deps = [ "//base", + "//components/gcm_driver", + "//components/gcm_driver/common", "//components/keyed_service/core", + "//components/ntp_snippets", "//components/offline_pages/core", + "//components/offline_pages/core:switches", "//net:net", "//url", ] @@ -62,11 +71,13 @@ "prefetch_request_operation_response_unittest.cc", "prefetch_request_test_base.cc", "prefetch_request_test_base.h", + "suggested_articles_observer_unittest.cc", ] deps = [ ":prefetch", "//components/offline_pages/core", + "//components/offline_pages/core:test_support", "//net:test_support", "//testing/gmock", "//testing/gtest",
diff --git a/components/offline_pages/core/prefetch/prefetch_gcm_app_handler.cc b/components/offline_pages/core/prefetch/prefetch_gcm_app_handler.cc new file mode 100644 index 0000000..e6baf087c --- /dev/null +++ b/components/offline_pages/core/prefetch/prefetch_gcm_app_handler.cc
@@ -0,0 +1,59 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/offline_pages/core/prefetch/prefetch_gcm_app_handler.h" + +#include "base/memory/ptr_util.h" +#include "components/offline_pages/core/prefetch/prefetch_service.h" + +namespace offline_pages { +namespace { +const char kPrefetchingOfflinePagesAppId[] = + "com.google.chrome.OfflinePagePrefetch"; +} + +PrefetchGCMAppHandler::PrefetchGCMAppHandler() {} +PrefetchGCMAppHandler::~PrefetchGCMAppHandler() = default; + +void PrefetchGCMAppHandler::ShutdownHandler() { + NOTIMPLEMENTED(); +} + +void PrefetchGCMAppHandler::OnStoreReset() { + NOTIMPLEMENTED(); +} + +void PrefetchGCMAppHandler::OnMessage(const std::string& app_id, + const gcm::IncomingMessage& message) { + NOTIMPLEMENTED(); +} + +void PrefetchGCMAppHandler::OnMessagesDeleted(const std::string& app_id) { + NOTIMPLEMENTED(); +} + +void PrefetchGCMAppHandler::OnSendError( + const std::string& app_id, + const gcm::GCMClient::SendErrorDetails& send_error_details) { + NOTIMPLEMENTED(); +} + +void PrefetchGCMAppHandler::OnSendAcknowledged(const std::string& app_id, + const std::string& message_id) { + NOTIMPLEMENTED(); +} + +bool PrefetchGCMAppHandler::CanHandle(const std::string& app_id) const { + return app_id == GetAppId(); +} + +gcm::GCMAppHandler* PrefetchGCMAppHandler::AsGCMAppHandler() { + return (gcm::GCMAppHandler*)this; +} + +std::string PrefetchGCMAppHandler::GetAppId() const { + return kPrefetchingOfflinePagesAppId; +} + +} // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/prefetch_gcm_app_handler.h b/components/offline_pages/core/prefetch/prefetch_gcm_app_handler.h new file mode 100644 index 0000000..beea579 --- /dev/null +++ b/components/offline_pages/core/prefetch/prefetch_gcm_app_handler.h
@@ -0,0 +1,50 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_GCM_APP_HANDLER_H_ +#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_GCM_APP_HANDLER_H_ + +#include <string> + +#include "components/gcm_driver/common/gcm_messages.h" +#include "components/gcm_driver/gcm_app_handler.h" +#include "components/gcm_driver/gcm_driver.h" +#include "components/gcm_driver/gcm_profile_service.h" +#include "components/offline_pages/core/prefetch/prefetch_gcm_handler.h" +#include "url/gurl.h" + +namespace offline_pages { + +// Receives GCM messages and other channel status messages on behalf of the +// prefetch system. +class PrefetchGCMAppHandler : public gcm::GCMAppHandler, + public PrefetchGCMHandler { + public: + PrefetchGCMAppHandler(); + ~PrefetchGCMAppHandler() override; + + // gcm::GCMAppHandler implementation. + void ShutdownHandler() override; + void OnStoreReset() override; + void OnMessage(const std::string& app_id, + const gcm::IncomingMessage& message) override; + void OnMessagesDeleted(const std::string& app_id) override; + void OnSendError( + const std::string& app_id, + const gcm::GCMClient::SendErrorDetails& send_error_details) override; + void OnSendAcknowledged(const std::string& app_id, + const std::string& message_id) override; + bool CanHandle(const std::string& app_id) const override; + + // offline_pages::PrefetchGCMHandler implementation. + gcm::GCMAppHandler* AsGCMAppHandler() override; + std::string GetAppId() const override; + + private: + DISALLOW_COPY_AND_ASSIGN(PrefetchGCMAppHandler); +}; + +} // namespace offline_pages + +#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_GCM_APP_HANDLER_H_
diff --git a/components/offline_pages/core/prefetch/prefetch_gcm_handler.h b/components/offline_pages/core/prefetch/prefetch_gcm_handler.h new file mode 100644 index 0000000..7ce70f41 --- /dev/null +++ b/components/offline_pages/core/prefetch/prefetch_gcm_handler.h
@@ -0,0 +1,37 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_GCM_HANDLER_H_ +#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_GCM_HANDLER_H_ + +#include <string> + +namespace gcm { +class GCMAppHandler; +} // namespace gcm + +namespace offline_pages { + +class PrefetchGCMHandler; + +// Main class and entry point for the Offline Pages Prefetching feature, that +// controls the lifetime of all major subcomponents of the prefetching system. +class PrefetchGCMHandler { + public: + virtual ~PrefetchGCMHandler() = default; + + // Returns the GCMAppHandler for this object. Can return |nullptr| in unit + // tests. + virtual gcm::GCMAppHandler* AsGCMAppHandler() = 0; + + // The app ID to register with at the GCM layer. + virtual std::string GetAppId() const = 0; + + // TODO(dewittj): Add methods for acquiring an Instance ID token to this + // interface. +}; + +} // namespace offline_pages + +#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_GCM_HANDLER_H_
diff --git a/components/offline_pages/core/prefetch/prefetch_service.h b/components/offline_pages/core/prefetch/prefetch_service.h index 9e5ec6c..5731dd25 100644 --- a/components/offline_pages/core/prefetch/prefetch_service.h +++ b/components/offline_pages/core/prefetch/prefetch_service.h
@@ -7,9 +7,14 @@ #include "components/keyed_service/core/keyed_service.h" +namespace ntp_snippets { +class ContentSuggestionsService; +} + namespace offline_pages { class PrefetchDispatcher; +class PrefetchGCMHandler; // Main class and entry point for the Offline Pages Prefetching feature, that // controls the lifetime of all major subcomponents of the prefetching system. @@ -18,6 +23,12 @@ ~PrefetchService() override = default; virtual PrefetchDispatcher* GetDispatcher() = 0; + virtual PrefetchGCMHandler* GetPrefetchGCMHandler() = 0; + + // Called at construction of the ContentSuggestionsService to begin observing + // events related to incoming articles. + virtual void ObserveContentSuggestionsService( + ntp_snippets::ContentSuggestionsService* service) = 0; }; } // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/prefetch_service_impl.cc b/components/offline_pages/core/prefetch/prefetch_service_impl.cc index 9e86aba..bf3a027 100644 --- a/components/offline_pages/core/prefetch/prefetch_service_impl.cc +++ b/components/offline_pages/core/prefetch/prefetch_service_impl.cc
@@ -11,14 +11,26 @@ namespace offline_pages { -PrefetchServiceImpl::PrefetchServiceImpl() - : dispatcher_(base::MakeUnique<PrefetchDispatcherImpl>()) {} +PrefetchServiceImpl::PrefetchServiceImpl( + std::unique_ptr<PrefetchGCMHandler> gcm_handler) + : gcm_handler_(std::move(gcm_handler)), + dispatcher_(base::MakeUnique<PrefetchDispatcherImpl>()) {} PrefetchServiceImpl::~PrefetchServiceImpl() = default; +PrefetchGCMHandler* PrefetchServiceImpl::GetPrefetchGCMHandler() { + return gcm_handler_.get(); +} + PrefetchDispatcher* PrefetchServiceImpl::GetDispatcher() { return dispatcher_.get(); -}; +} + +void PrefetchServiceImpl::ObserveContentSuggestionsService( + ntp_snippets::ContentSuggestionsService* service) { + suggested_articles_observer_ = + base::MakeUnique<SuggestedArticlesObserver>(service, this); +} void PrefetchServiceImpl::Shutdown() {}
diff --git a/components/offline_pages/core/prefetch/prefetch_service_impl.h b/components/offline_pages/core/prefetch/prefetch_service_impl.h index c476f13..cb50f9421 100644 --- a/components/offline_pages/core/prefetch/prefetch_service_impl.h +++ b/components/offline_pages/core/prefetch/prefetch_service_impl.h
@@ -8,22 +8,33 @@ #include <memory> #include "base/macros.h" +#include "components/offline_pages/core/prefetch/prefetch_gcm_handler.h" #include "components/offline_pages/core/prefetch/prefetch_service.h" +#include "components/offline_pages/core/prefetch/suggested_articles_observer.h" + +namespace ntp_snippets { +class ContentSuggestionsService; +} namespace offline_pages { class PrefetchServiceImpl : public PrefetchService { public: - PrefetchServiceImpl(); + PrefetchServiceImpl(std::unique_ptr<PrefetchGCMHandler> gcm_handler); ~PrefetchServiceImpl() override; // PrefetchService implementation: + void ObserveContentSuggestionsService( + ntp_snippets::ContentSuggestionsService* service) override; PrefetchDispatcher* GetDispatcher() override; + PrefetchGCMHandler* GetPrefetchGCMHandler() override; // KeyedService implementation: void Shutdown() override; private: + std::unique_ptr<SuggestedArticlesObserver> suggested_articles_observer_; + std::unique_ptr<PrefetchGCMHandler> gcm_handler_; std::unique_ptr<PrefetchDispatcher> dispatcher_; DISALLOW_COPY_AND_ASSIGN(PrefetchServiceImpl);
diff --git a/components/offline_pages/core/prefetch/prefetch_service_impl_unittest.cc b/components/offline_pages/core/prefetch/prefetch_service_impl_unittest.cc new file mode 100644 index 0000000..5dfee742 --- /dev/null +++ b/components/offline_pages/core/prefetch/prefetch_service_impl_unittest.cc
@@ -0,0 +1,21 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/offline_pages/core/prefetch/prefetch_service_impl.h" + +#include "components/offline_pages/core/client_namespace_constants.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace offline_pages { + +TEST(PrefetchServiceTest, ServiceDoesNotCrash) { + PrefetchServiceImpl service(nullptr); + + service.AddCandidatePrefetchURLs(std::vector<PrefetchService::PrefetchURL>()); + service.RemoveAllUnprocessedPrefetchURLs(kSuggestedArticlesNamespace); + service.RemovePrefetchURLsByClientId({kSuggestedArticlesNamespace, "123"}); +} + +} // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/suggested_articles_observer.cc b/components/offline_pages/core/prefetch/suggested_articles_observer.cc new file mode 100644 index 0000000..2a1990e6 --- /dev/null +++ b/components/offline_pages/core/prefetch/suggested_articles_observer.cc
@@ -0,0 +1,115 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/offline_pages/core/prefetch/suggested_articles_observer.h" + +#include <unordered_set> + +#include "base/memory/ptr_util.h" +#include "components/ntp_snippets/category.h" +#include "components/ntp_snippets/category_status.h" +#include "components/offline_pages/core/client_namespace_constants.h" +#include "components/offline_pages/core/offline_page_feature.h" +#include "components/offline_pages/core/offline_page_item.h" +#include "components/offline_pages/core/prefetch/prefetch_dispatcher.h" +#include "components/offline_pages/core/prefetch/prefetch_service_impl.h" + +using ntp_snippets::Category; +using ntp_snippets::ContentSuggestion; + +namespace offline_pages { + +namespace { + +const ntp_snippets::Category& ArticlesCategory() { + static ntp_snippets::Category articles = + Category::FromKnownCategory(ntp_snippets::KnownCategories::ARTICLES); + return articles; +} + +ClientId CreateClientIDFromSuggestionId(const ContentSuggestion::ID& id) { + return ClientId(kSuggestedArticlesNamespace, id.id_within_category()); +} + +} // namespace + +SuggestedArticlesObserver::SuggestedArticlesObserver( + ntp_snippets::ContentSuggestionsService* content_suggestions_service, + PrefetchService* prefetch_service) + : content_suggestions_service_(content_suggestions_service), + prefetch_service_(prefetch_service) { + // The content suggestions service can be |nullptr| in tests. + if (content_suggestions_service_) + content_suggestions_service_->AddObserver(this); +} + +SuggestedArticlesObserver::~SuggestedArticlesObserver() = default; + +void SuggestedArticlesObserver::OnNewSuggestions(Category category) { + // TODO(dewittj): Change this to check whether a given category is not + // a _remote_ category. + if (category != ArticlesCategory() || + category_status_ != ntp_snippets::CategoryStatus::AVAILABLE) { + return; + } + + const std::vector<ContentSuggestion>& suggestions = + test_articles_ ? *test_articles_ + : content_suggestions_service_->GetSuggestionsForCategory( + ArticlesCategory()); + if (suggestions.empty()) + return; + + std::vector<PrefetchDispatcher::PrefetchURL> prefetch_urls; + for (const ContentSuggestion& suggestion : suggestions) { + prefetch_urls.push_back( + {CreateClientIDFromSuggestionId(suggestion.id()), suggestion.url()}); + } + + prefetch_service_->GetDispatcher()->AddCandidatePrefetchURLs(prefetch_urls); +} + +void SuggestedArticlesObserver::OnCategoryStatusChanged( + Category category, + ntp_snippets::CategoryStatus new_status) { + if (category != ArticlesCategory() || category_status_ == new_status) + return; + + category_status_ = new_status; + + if (category_status_ == + ntp_snippets::CategoryStatus::CATEGORY_EXPLICITLY_DISABLED || + category_status_ == + ntp_snippets::CategoryStatus::ALL_SUGGESTIONS_EXPLICITLY_DISABLED) { + prefetch_service_->GetDispatcher()->RemoveAllUnprocessedPrefetchURLs( + kSuggestedArticlesNamespace); + } +} + +void SuggestedArticlesObserver::OnSuggestionInvalidated( + const ContentSuggestion::ID& suggestion_id) { + prefetch_service_->GetDispatcher()->RemovePrefetchURLsByClientId( + CreateClientIDFromSuggestionId(suggestion_id)); +} + +void SuggestedArticlesObserver::OnFullRefreshRequired() { + prefetch_service_->GetDispatcher()->RemoveAllUnprocessedPrefetchURLs( + kSuggestedArticlesNamespace); + OnNewSuggestions(ArticlesCategory()); +} + +void SuggestedArticlesObserver::ContentSuggestionsServiceShutdown() { + // No need to do anything here, we will just stop getting events. +} + +std::vector<ntp_snippets::ContentSuggestion>* +SuggestedArticlesObserver::GetTestingArticles() { + if (!test_articles_) { + test_articles_ = + base::MakeUnique<std::vector<ntp_snippets::ContentSuggestion>>(); + } + return test_articles_.get(); +} + +} // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/suggested_articles_observer.h b/components/offline_pages/core/prefetch/suggested_articles_observer.h new file mode 100644 index 0000000..1af83d71 --- /dev/null +++ b/components/offline_pages/core/prefetch/suggested_articles_observer.h
@@ -0,0 +1,67 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_SUGGESTED_ARTICLES_OBSERVER_H_ +#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_SUGGESTED_ARTICLES_OBSERVER_H_ + +#include <memory> + +#include "base/callback.h" +#include "base/memory/weak_ptr.h" +#include "components/ntp_snippets/content_suggestions_service.h" +#include "components/offline_pages/core/prefetch/prefetch_service.h" + +namespace ntp_snippets { +class Category; +} + +namespace offline_pages { + +// Observes the ContentSuggestionsService, listening for new suggestions in the +// ARTICLES category. When those suggestions arrive, it then forwards them to +// the Prefetch Service, which does not know about Content Suggestions +// specifically. +class SuggestedArticlesObserver + : public ntp_snippets::ContentSuggestionsService::Observer { + public: + SuggestedArticlesObserver( + // This can be |nullptr| in test. + ntp_snippets::ContentSuggestionsService* content_suggestions_service, + PrefetchService* prefetch_service); + ~SuggestedArticlesObserver() override; + + // ContentSuggestionsService::Observer overrides. + void OnNewSuggestions(ntp_snippets::Category category) override; + void OnCategoryStatusChanged( + ntp_snippets::Category category, + ntp_snippets::CategoryStatus new_status) override; + void OnSuggestionInvalidated( + const ntp_snippets::ContentSuggestion::ID& suggestion_id) override; + void OnFullRefreshRequired() override; + void ContentSuggestionsServiceShutdown() override; + + // Returns a pointer to the list of testing articles. If there is no such + // list, allocates one before returning the list. The observer owns the list. + std::vector<ntp_snippets::ContentSuggestion>* GetTestingArticles(); + + private: + // Unowned, only used when we are called by observer methods (so the + // pointer will be valid). + ntp_snippets::ContentSuggestionsService* content_suggestions_service_; + + // This class is owned by the prefetch service. + PrefetchService* prefetch_service_; + + // Normally null, but can be set in tests to override the default behavior. + std::unique_ptr<std::vector<ntp_snippets::ContentSuggestion>> test_articles_; + + ntp_snippets::CategoryStatus category_status_ = + ntp_snippets::CategoryStatus::INITIALIZING; + + DISALLOW_COPY_AND_ASSIGN(SuggestedArticlesObserver); +}; + +} // namespace offline_pages + +#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_SUGGESTED_ARTICLES_OBSERVER_H_
diff --git a/components/offline_pages/content/suggested_articles_observer_unittest.cc b/components/offline_pages/core/prefetch/suggested_articles_observer_unittest.cc similarity index 69% rename from components/offline_pages/content/suggested_articles_observer_unittest.cc rename to components/offline_pages/core/prefetch/suggested_articles_observer_unittest.cc index 6fae70d8..99595db 100644 --- a/components/offline_pages/content/suggested_articles_observer_unittest.cc +++ b/components/offline_pages/core/prefetch/suggested_articles_observer_unittest.cc
@@ -2,16 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/offline_pages/content/suggested_articles_observer.h" +#include "components/offline_pages/core/prefetch/suggested_articles_observer.h" #include "base/run_loop.h" #include "base/test/test_simple_task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "components/offline_pages/core/client_namespace_constants.h" #include "components/offline_pages/core/prefetch/prefetch_dispatcher.h" +#include "components/offline_pages/core/prefetch/prefetch_gcm_app_handler.h" #include "components/offline_pages/core/prefetch/prefetch_service.h" #include "components/offline_pages/core/stub_offline_page_model.h" -#include "content/public/test/test_browser_context.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" @@ -67,36 +67,13 @@ public: TestingPrefetchService() = default; + PrefetchGCMHandler* GetPrefetchGCMHandler() override { return nullptr; } PrefetchDispatcher* GetDispatcher() override { return &dispatcher; }; - + void ObserveContentSuggestionsService( + ntp_snippets::ContentSuggestionsService* content_suggestions_service) + override {} TestingPrefetchDispatcher dispatcher; }; - -class TestDelegate : public SuggestedArticlesObserver::Delegate { - public: - TestDelegate() = default; - ~TestDelegate() override = default; - - const std::vector<ContentSuggestion>& GetSuggestions( - const Category& category) override { - get_suggestions_count++; - return suggestions; - } - - PrefetchService* GetPrefetchService( - content::BrowserContext* context) override { - return &prefetch_service; - } - - TestingPrefetchService prefetch_service; - - // Public for test manipulation. - std::vector<ContentSuggestion> suggestions; - - // Signals that delegate was called. - int get_suggestions_count = 0; -}; - } // namespace class OfflinePageSuggestedArticlesObserverTest : public testing::Test { @@ -104,23 +81,13 @@ OfflinePageSuggestedArticlesObserverTest() = default; void SetUp() override { - observer_ = - base::MakeUnique<SuggestedArticlesObserver>(&context_, MakeDelegate()); - } - - virtual std::unique_ptr<SuggestedArticlesObserver::Delegate> MakeDelegate() { - auto delegate_ptr = base::MakeUnique<TestDelegate>(); - test_delegate_ = delegate_ptr.get(); - return std::move(delegate_ptr); + observer_ = base::MakeUnique<SuggestedArticlesObserver>( + nullptr, test_prefetch_service()); } SuggestedArticlesObserver* observer() { return observer_.get(); } - TestDelegate* test_delegate() { return test_delegate_; } - - TestingPrefetchService* test_prefetch_service() { - return &(test_delegate()->prefetch_service); - } + TestingPrefetchService* test_prefetch_service() { return &prefetch_service_; } TestingPrefetchDispatcher* test_prefetch_dispatcher() { return &(test_prefetch_service()->dispatcher); @@ -129,36 +96,16 @@ protected: Category category = Category::FromKnownCategory(ntp_snippets::KnownCategories::ARTICLES); - content::TestBrowserContext context_; private: std::unique_ptr<SuggestedArticlesObserver> observer_; - TestDelegate* test_delegate_; + TestingPrefetchService prefetch_service_; }; TEST_F(OfflinePageSuggestedArticlesObserverTest, - CallsDelegateOnNewSuggestions) { - // We should not do anything if the category is not loaded. - observer()->OnNewSuggestions(category); - EXPECT_EQ(0, test_delegate()->get_suggestions_count); - EXPECT_EQ(0, test_prefetch_dispatcher()->new_suggestions_count); - - // Once the category becomes available, new suggestions should cause us to ask - // the delegate for suggestion URLs. - observer()->OnCategoryStatusChanged(category, - ntp_snippets::CategoryStatus::AVAILABLE); - observer()->OnNewSuggestions(category); - EXPECT_EQ(1, test_delegate()->get_suggestions_count); - - // We expect that no pages were forwarded to the prefetch service since no - // pages were prepopulated. - EXPECT_EQ(0, test_prefetch_dispatcher()->new_suggestions_count); -} - -TEST_F(OfflinePageSuggestedArticlesObserverTest, ForwardsSuggestionsToPrefetchService) { const GURL test_url_1("https://www.example.com/1"); - test_delegate()->suggestions.push_back( + observer()->GetTestingArticles()->push_back( ContentSuggestionFromTestURL(test_url_1)); observer()->OnCategoryStatusChanged(category, @@ -176,9 +123,9 @@ TEST_F(OfflinePageSuggestedArticlesObserverTest, RemovesAllOnBadStatus) { const GURL test_url_1("https://www.example.com/1"); const GURL test_url_2("https://www.example.com/2"); - test_delegate()->suggestions.push_back( + observer()->GetTestingArticles()->push_back( ContentSuggestionFromTestURL(test_url_1)); - test_delegate()->suggestions.push_back( + observer()->GetTestingArticles()->push_back( ContentSuggestionFromTestURL(test_url_2)); observer()->OnCategoryStatusChanged(category, @@ -197,7 +144,7 @@ TEST_F(OfflinePageSuggestedArticlesObserverTest, RemovesClientIdOnInvalidated) { const GURL test_url_1("https://www.example.com/1"); - test_delegate()->suggestions.push_back( + observer()->GetTestingArticles()->push_back( ContentSuggestionFromTestURL(test_url_1)); observer()->OnCategoryStatusChanged(category, ntp_snippets::CategoryStatus::AVAILABLE);
diff --git a/components/sync/OWNERS b/components/sync/OWNERS index 7f146cf..5e1a5c4 100644 --- a/components/sync/OWNERS +++ b/components/sync/OWNERS
@@ -1,4 +1,3 @@ -maxbogue@chromium.org pavely@chromium.org skym@chromium.org stanisc@chromium.org
diff --git a/components/sync/engine_impl/sync_scheduler_impl.cc b/components/sync/engine_impl/sync_scheduler_impl.cc index 4c5ebce..c2055eb 100644 --- a/components/sync/engine_impl/sync_scheduler_impl.cc +++ b/components/sync/engine_impl/sync_scheduler_impl.cc
@@ -774,14 +774,15 @@ void SyncSchedulerImpl::PerformDelayedNudge() { // Circumstances may have changed since we scheduled this delayed nudge. // We must check to see if it's OK to run the job before we do so. - if (CanRunNudgeJobNow(NORMAL_PRIORITY)) + if (CanRunNudgeJobNow(NORMAL_PRIORITY)) { TrySyncCycleJob(); - - // We're not responsible for setting up any retries here. The functions that - // first put us into a state that prevents successful sync cycles (eg. global - // throttling, type throttling, network errors, transient errors) will also - // setup the appropriate retry logic (eg. retry after timeout, exponential - // backoff, retry when the network changes). + } else { + // If we set |waiting_interal_| while this PerformDelayedNudge was pending + // callback scheduled to |retry_timer_|, it's possible we didn't re-schedule + // because this PerformDelayedNudge was going to execute sooner. If that's + // the case, we need to make sure we setup to waiting callback now. + RestartWaiting(); + } } void SyncSchedulerImpl::ExponentialBackoffRetry() {
diff --git a/components/sync/engine_impl/sync_scheduler_impl_unittest.cc b/components/sync/engine_impl/sync_scheduler_impl_unittest.cc index fa5e417..71493bd 100644 --- a/components/sync/engine_impl/sync_scheduler_impl_unittest.cc +++ b/components/sync/engine_impl/sync_scheduler_impl_unittest.cc
@@ -83,7 +83,7 @@ RunLoop(); } -void PumpLoopFor(base::TimeDelta time) { +void PumpLoopFor(TimeDelta time) { // Allow the loop to run for the specified amount of time. base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, base::Bind(&QuitLoopNow), time); @@ -245,7 +245,7 @@ return scheduler_->nudge_tracker_.IsAnyTypeBlocked(); } - base::TimeDelta GetRetryTimerDelay() { + TimeDelta GetRetryTimerDelay() { EXPECT_TRUE(scheduler_->retry_timer_.IsRunning()); return scheduler_->retry_timer_.GetCurrentDelay(); } @@ -256,7 +256,7 @@ return MockInvalidation::Build(version, payload); } - base::TimeDelta GetTypeBlockingTime(ModelType type) { + TimeDelta GetTypeBlockingTime(ModelType type) { NudgeTracker::TypeTrackerMap::const_iterator tracker_it = scheduler_->nudge_tracker_.type_trackers_.find(type); DCHECK(tracker_it != scheduler_->nudge_tracker_.type_trackers_.end()); @@ -285,6 +285,11 @@ return scheduler_->pending_wakeup_timer_.IsRunning(); } + TimeDelta GetPendingWakeupTimerDelay() { + EXPECT_TRUE(scheduler_->pending_wakeup_timer_.IsRunning()); + return scheduler_->pending_wakeup_timer_.GetCurrentDelay(); + } + private: syncable::Directory* directory() { return test_user_share_.user_share()->directory.get(); @@ -714,7 +719,7 @@ // Set the start time to |poll_interval| in the future. TimeTicks optimal_start = TimeTicks::Now() + poll_interval; - StartSyncScheduler(base::Time::Now() + base::TimeDelta::FromMinutes(10)); + StartSyncScheduler(base::Time::Now() + TimeDelta::FromMinutes(10)); // Run again to wait for polling. RunLoop(); @@ -1448,7 +1453,7 @@ // The new optimal time is now, since the desired poll should have happened // in the past. - optimal_job_time = base::TimeTicks::Now(); + optimal_job_time = TimeTicks::Now(); RunLoop(); Mock::VerifyAndClearExpectations(syncer()); ASSERT_EQ(kMinNumSamples, times.size()); @@ -1627,7 +1632,7 @@ StartSyncScheduler(base::Time()); SyncShareTimes times; - base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10); + TimeDelta delay = TimeDelta::FromMilliseconds(10); scheduler()->OnReceivedGuRetryDelay(delay); EXPECT_EQ(delay, GetRetryTimerDelay()); @@ -1650,7 +1655,7 @@ StartSyncScheduler(base::Time()); - base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10); + TimeDelta delay = TimeDelta::FromMilliseconds(10); scheduler()->OnReceivedGuRetryDelay(delay); EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) @@ -1679,8 +1684,8 @@ StartSyncScheduler(base::Time()); SyncShareTimes times; - base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(100); - base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(200); + TimeDelta delay1 = TimeDelta::FromMilliseconds(100); + TimeDelta delay2 = TimeDelta::FromMilliseconds(200); scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE); scheduler()->OnReceivedGuRetryDelay(delay1); @@ -1761,14 +1766,14 @@ EXPECT_TRUE(GetBackedOffTypes().HasAll(types)); EXPECT_FALSE(scheduler()->IsBackingOff()); EXPECT_FALSE(scheduler()->IsCurrentlyThrottled()); - base::TimeDelta first_blocking_time = GetTypeBlockingTime(THEMES); + TimeDelta first_blocking_time = GetTypeBlockingTime(THEMES); SetTypeBlockingMode(THEMES, WaitInterval::EXPONENTIAL_BACKOFF_RETRYING); // This won't cause a sync cycle because the types are backed off. scheduler()->ScheduleLocalNudge(types, FROM_HERE); PumpLoop(); PumpLoop(); - base::TimeDelta second_blocking_time = GetTypeBlockingTime(THEMES); + TimeDelta second_blocking_time = GetTypeBlockingTime(THEMES); // The Exponential backoff should be between previous backoff 1.5 and 2.5 // times. @@ -1900,4 +1905,48 @@ StopSyncScheduler(); } +TEST_F(SyncSchedulerImplTest, InterleavedNudgesStillRestart) { + UseMockDelayProvider(); + EXPECT_CALL(*delay(), GetDelay(_)) + .WillOnce(Return(long_delay())) + .RetiresOnSaturation(); + TimeDelta poll(TimeDelta::FromDays(1)); + scheduler()->OnReceivedLongPollIntervalUpdate(poll); + + StartSyncScheduler(base::Time()); + scheduler()->ScheduleLocalNudge({THEMES}, FROM_HERE); + PumpLoop(); // To get PerformDelayedNudge called. + EXPECT_FALSE(BlockTimerIsRunning()); + EXPECT_FALSE(scheduler()->IsBackingOff()); + + // This is the tricky piece. We have a gap while the sync job is bouncing to + // get onto the |pending_wakeup_timer_|, should be scheduled with no delay. + scheduler()->ScheduleLocalNudge({TYPED_URLS}, FROM_HERE); + EXPECT_TRUE(BlockTimerIsRunning()); + EXPECT_EQ(TimeDelta(), GetPendingWakeupTimerDelay()); + EXPECT_FALSE(scheduler()->IsBackingOff()); + + // Setup mock as we're about to attempt to sync. + SyncShareTimes times; + EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) + .WillOnce(DoAll(Invoke(test_util::SimulateCommitFailed), + RecordSyncShare(×, false))); + // Triggers the THEMES TrySyncCycleJobImpl(), which we've setup to fail. Its + // RestartWaiting won't schedule a delayed retry, as the TYPED_URLS nudge has + // a smaller delay. We verify this by making sure the delay is still zero. + PumpLoop(); + EXPECT_TRUE(BlockTimerIsRunning()); + EXPECT_EQ(TimeDelta(), GetPendingWakeupTimerDelay()); + EXPECT_TRUE(scheduler()->IsBackingOff()); + + // Triggers TYPED_URLS PerformDelayedNudge(), which should no-op, because + // we're no long healthy, and normal priorities shouldn't go through, but it + // does need to setup the |pending_wakeup_timer_|. The delay should be ~60 + // seconds, so verifying it's greater than 50 should be safe. + PumpLoop(); + EXPECT_TRUE(BlockTimerIsRunning()); + EXPECT_LT(TimeDelta::FromSeconds(50), GetPendingWakeupTimerDelay()); + EXPECT_TRUE(scheduler()->IsBackingOff()); +} + } // namespace syncer
diff --git a/content/browser/accessibility/browser_accessibility_com_win.cc b/content/browser/accessibility/browser_accessibility_com_win.cc index bc22482..69a6ed8 100644 --- a/content/browser/accessibility/browser_accessibility_com_win.cc +++ b/content/browser/accessibility/browser_accessibility_com_win.cc
@@ -633,21 +633,7 @@ if (!owner()) return E_FAIL; - if (!role) - return E_INVALIDARG; - - BrowserAccessibilityComWin* target = GetTargetFromChildID(var_id); - if (!target) - return E_INVALIDARG; - - if (!target->role_name().empty()) { - role->vt = VT_BSTR; - role->bstrVal = SysAllocString(target->role_name().c_str()); - } else { - role->vt = VT_I4; - role->lVal = target->ia_role(); - } - return S_OK; + return AXPlatformNodeWin::get_accRole(var_id, role); } STDMETHODIMP BrowserAccessibilityComWin::get_accState(VARIANT var_id,
diff --git a/content/browser/frame_host/cross_process_frame_connector.cc b/content/browser/frame_host/cross_process_frame_connector.cc index 1ca49b4..50d8b58 100644 --- a/content/browser/frame_host/cross_process_frame_connector.cc +++ b/content/browser/frame_host/cross_process_frame_connector.cc
@@ -246,6 +246,7 @@ void CrossProcessFrameConnector::OnUpdateViewportIntersection( const gfx::Rect& viewport_intersection) { + viewport_intersection_rect_ = viewport_intersection; if (view_) view_->UpdateViewportIntersection(viewport_intersection); }
diff --git a/content/browser/frame_host/cross_process_frame_connector.h b/content/browser/frame_host/cross_process_frame_connector.h index 641a5100..3a7d977 100644 --- a/content/browser/frame_host/cross_process_frame_connector.h +++ b/content/browser/frame_host/cross_process_frame_connector.h
@@ -133,12 +133,18 @@ // Returns the view for the top-level frame under the same WebContents. RenderWidgetHostViewBase* GetRootRenderWidgetHostView(); + const gfx::Rect& viewport_intersection() const { + return viewport_intersection_rect_; + } + // Exposed for tests. RenderWidgetHostViewBase* GetRootRenderWidgetHostViewForTesting() { return GetRootRenderWidgetHostView(); } private: + friend class MockCrossProcessFrameConnector; + // Handlers for messages received from the parent frame. void OnFrameRectChanged(const gfx::Rect& frame_rect); void OnUpdateViewportIntersection(const gfx::Rect& viewport_intersection); @@ -157,6 +163,7 @@ RenderWidgetHostViewChildFrame* view_; gfx::Rect child_frame_rect_; + gfx::Rect viewport_intersection_rect_; bool is_scroll_bubbling_; };
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.cc b/content/browser/frame_host/render_widget_host_view_child_frame.cc index b979394..cbd7258 100644 --- a/content/browser/frame_host/render_widget_host_view_child_frame.cc +++ b/content/browser/frame_host/render_widget_host_view_child_frame.cc
@@ -614,6 +614,11 @@ return true; } +void RenderWidgetHostViewChildFrame::WillSendScreenRects() { + if (frame_connector_) + UpdateViewportIntersection(frame_connector_->viewport_intersection()); +} + #if defined(OS_MACOSX) ui::AcceleratedWidgetMac* RenderWidgetHostViewChildFrame::GetAcceleratedWidgetMac() const {
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.h b/content/browser/frame_host/render_widget_host_view_child_frame.h index 70a3b2fc..e7c5915 100644 --- a/content/browser/frame_host/render_widget_host_view_child_frame.h +++ b/content/browser/frame_host/render_widget_host_view_child_frame.h
@@ -151,6 +151,8 @@ bool IsRenderWidgetHostViewChildFrame() override; + void WillSendScreenRects() override; + #if defined(OS_MACOSX) // RenderWidgetHostView implementation. ui::AcceleratedWidgetMac* GetAcceleratedWidgetMac() const override;
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame_unittest.cc b/content/browser/frame_host/render_widget_host_view_child_frame_unittest.cc index 3c04ce9..d589fd2 100644 --- a/content/browser/frame_host/render_widget_host_view_child_frame_unittest.cc +++ b/content/browser/frame_host/render_widget_host_view_child_frame_unittest.cc
@@ -53,6 +53,8 @@ void SelectAll() override {} }; +} // namespace + class MockCrossProcessFrameConnector : public CrossProcessFrameConnector { public: MockCrossProcessFrameConnector() : CrossProcessFrameConnector(nullptr) {} @@ -63,6 +65,10 @@ last_surface_info_ = surface_info; } + void SetViewportIntersection(const gfx::Rect& intersection) { + viewport_intersection_rect_ = intersection; + } + RenderWidgetHostViewBase* GetParentRenderWidgetHostView() override { return nullptr; } @@ -70,8 +76,6 @@ cc::SurfaceInfo last_surface_info_; }; -} // namespace - class RenderWidgetHostViewChildFrameTest : public testing::Test { public: RenderWidgetHostViewChildFrameTest() @@ -244,4 +248,25 @@ EXPECT_TRUE(view_->has_frame()); } +// Tests that the viewport intersection rect is dispatched to the RenderWidget +// whenever screen rects are updated. +TEST_F(RenderWidgetHostViewChildFrameTest, ViewportIntersectionUpdated) { + gfx::Rect intersection_rect(5, 5, 100, 80); + test_frame_connector_->SetViewportIntersection(intersection_rect); + + MockRenderProcessHost* process = + static_cast<MockRenderProcessHost*>(widget_host_->GetProcess()); + process->Init(); + + widget_host_->Init(); + + const IPC::Message* intersection_update = + process->sink().GetUniqueMessageMatching( + ViewMsg_SetViewportIntersection::ID); + ASSERT_TRUE(intersection_update); + std::tuple<gfx::Rect> sent_rect; + ViewMsg_SetViewportIntersection::Read(intersection_update, &sent_rect); + EXPECT_EQ(intersection_rect, std::get<0>(sent_rect)); +} + } // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index 7556afa..4e79b0bf 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -485,6 +485,7 @@ last_view_screen_rect_ = view_->GetViewBounds(); last_window_screen_rect_ = view_->GetBoundsInRootWindow(); + view_->WillSendScreenRects(); Send(new ViewMsg_UpdateScreenRects( GetRoutingID(), last_view_screen_rect_, last_window_screen_rect_)); waiting_for_screen_rects_ack_ = true;
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h index 1f1a6b9..3f7581a 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.h +++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -317,6 +317,10 @@ // need to also be resolved. virtual bool IsRenderWidgetHostViewChildFrame(); + // Notify the View that a screen rect update is being sent to the + // RenderWidget. Related platform-specific updates can be sent from here. + virtual void WillSendScreenRects() {} + // Returns true if the current view is in virtual reality mode. virtual bool IsInVR() const;
diff --git a/content/child/web_url_loader_impl.cc b/content/child/web_url_loader_impl.cc index 0bf318d..73e4dee6 100644 --- a/content/child/web_url_loader_impl.cc +++ b/content/child/web_url_loader_impl.cc
@@ -1216,6 +1216,7 @@ new_request.SetShouldResetAppCache(request.ShouldResetAppCache()); new_request.SetFetchRequestMode(request.GetFetchRequestMode()); new_request.SetFetchCredentialsMode(request.GetFetchCredentialsMode()); + new_request.SetKeepalive(request.GetKeepalive()); new_request.SetHTTPReferrer(WebString::FromUTF8(redirect_info.new_referrer), NetReferrerPolicyToBlinkReferrerPolicy(
diff --git a/content/public/android/java/src/org/chromium/content/browser/SpeechRecognition.java b/content/public/android/java/src/org/chromium/content/browser/SpeechRecognition.java index 7ddb2bc..90aeb60f 100644 --- a/content/public/android/java/src/org/chromium/content/browser/SpeechRecognition.java +++ b/content/public/android/java/src/org/chromium/content/browser/SpeechRecognition.java
@@ -18,6 +18,7 @@ import android.speech.SpeechRecognizer; import org.chromium.base.ContextUtils; +import org.chromium.base.Log; import org.chromium.base.PackageUtils; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; @@ -33,6 +34,7 @@ */ @JNINamespace("content") public class SpeechRecognition { + private static final String TAG = "SpeechRecog"; // Constants describing the speech recognition provider we depend on. private static final String PROVIDER_PACKAGE_NAME = "com.google.android.googlequicksearchbox"; @@ -239,7 +241,13 @@ nativeOnRecognitionError(mNativeSpeechRecognizerImplAndroid, error); } - mRecognizer.destroy(); + try { + mRecognizer.destroy(); + } catch (IllegalArgumentException e) { + // Intentionally swallow exception. This incorrectly throws exception on some samsung + // devices, causing crashes. + Log.w(TAG, "Destroy threw exception " + mRecognizer, e); + } mRecognizer = null; nativeOnRecognitionEnd(mNativeSpeechRecognizerImplAndroid); mNativeSpeechRecognizerImplAndroid = 0;
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn index 04aafe1..6e68d6f 100644 --- a/extensions/browser/BUILD.gn +++ b/extensions/browser/BUILD.gn
@@ -252,6 +252,7 @@ deps = [ "//base:i18n", "//components/cast_certificate", + "//components/cast_channel", "//components/crx_file", "//components/guest_view/browser", "//components/keyed_service/content", @@ -396,6 +397,7 @@ "api/bluetooth/bluetooth_event_router_unittest.cc", "api/cast_channel/cast_auth_util_unittest.cc", "api/cast_channel/cast_channel_api_unittest.cc", + "api/cast_channel/cast_channel_enum_util_unittest.cc", "api/cast_channel/cast_framer_unittest.cc", "api/cast_channel/cast_socket_service_unittest.cc", "api/cast_channel/cast_socket_unittest.cc",
diff --git a/extensions/browser/api/cast_channel/BUILD.gn b/extensions/browser/api/cast_channel/BUILD.gn index 40ff859..6ec14193 100644 --- a/extensions/browser/api/cast_channel/BUILD.gn +++ b/extensions/browser/api/cast_channel/BUILD.gn
@@ -8,6 +8,8 @@ "cast_auth_util.h", "cast_channel_api.cc", "cast_channel_api.h", + "cast_channel_enum_util.cc", + "cast_channel_enum_util.h", "cast_framer.cc", "cast_framer.h", "cast_message_util.cc", @@ -28,6 +30,7 @@ deps = [ "//base", + "//components/cast_channel", "//extensions/common/api", "//extensions/common/api/cast_channel:cast_channel_proto", "//net",
diff --git a/extensions/browser/api/cast_channel/DEPS b/extensions/browser/api/cast_channel/DEPS index 23ace86e..44ac277a 100644 --- a/extensions/browser/api/cast_channel/DEPS +++ b/extensions/browser/api/cast_channel/DEPS
@@ -1,4 +1,5 @@ include_rules = [ "+components/cast_certificate", + "+components/cast_channel", "+third_party/zlib", ]
diff --git a/extensions/browser/api/cast_channel/cast_channel_api.cc b/extensions/browser/api/cast_channel/cast_channel_api.cc index cb5078d5a..b645aed 100644 --- a/extensions/browser/api/cast_channel/cast_channel_api.cc +++ b/extensions/browser/api/cast_channel/cast_channel_api.cc
@@ -19,6 +19,7 @@ #include "base/strings/string_number_conversions.h" #include "base/values.h" #include "content/public/browser/browser_thread.h" +#include "extensions/browser/api/cast_channel/cast_channel_enum_util.h" #include "extensions/browser/api/cast_channel/cast_message_util.h" #include "extensions/browser/api/cast_channel/cast_socket.h" #include "extensions/browser/api/cast_channel/cast_socket_service.h" @@ -43,18 +44,19 @@ namespace OnMessage = cast_channel::OnMessage; namespace Open = cast_channel::Open; namespace Send = cast_channel::Send; +using ::cast_channel::ChannelError; using cast_channel::CastDeviceCapability; using cast_channel::CastMessage; using cast_channel::CastSocket; -using cast_channel::ChannelAuthType; -using cast_channel::ChannelError; +using cast_channel::CastSocketImpl; +using cast_channel::CastTransport; using cast_channel::ChannelInfo; using cast_channel::ConnectInfo; using cast_channel::ErrorInfo; +using cast_channel::KeepAliveDelegate; using cast_channel::LastErrors; using cast_channel::Logger; using cast_channel::MessageInfo; -using cast_channel::ReadyState; using content::BrowserThread; namespace { @@ -75,15 +77,17 @@ const net::IPEndPoint& ip_endpoint = socket.ip_endpoint(); channel_info->connect_info.ip_address = ip_endpoint.ToStringWithoutPort(); channel_info->connect_info.port = ip_endpoint.port(); - channel_info->connect_info.auth = socket.channel_auth(); - channel_info->ready_state = socket.ready_state(); - channel_info->error_state = socket.error_state(); + channel_info->connect_info.auth = + cast_channel::ToChannelAuthType(socket.channel_auth()); + channel_info->ready_state = cast_channel::ToReadyState(socket.ready_state()); + channel_info->error_state = + cast_channel::ToChannelError(socket.error_state()); channel_info->keep_alive = socket.keep_alive(); channel_info->audio_only = socket.audio_only(); } // Fills |error_info| from |error_state| and |last_errors|. -void FillErrorInfo(ChannelError error_state, +void FillErrorInfo(cast_channel::ChannelError error_state, const LastErrors& last_errors, ErrorInfo* error_info) { error_info->error_state = error_state; @@ -209,15 +213,17 @@ const CastSocket& socket) { ChannelInfo channel_info; FillChannelInfo(socket, &channel_info); - ChannelError error = socket.error_state(); + cast_channel::ChannelError error = + cast_channel::ToChannelError(socket.error_state()); if (error != cast_channel::CHANNEL_ERROR_NONE) { SetError("Channel socket error = " + base::IntToString(error)); } SetResultFromChannelInfo(channel_info); } -void CastChannelAsyncApiFunction::SetResultFromError(int channel_id, - ChannelError error) { +void CastChannelAsyncApiFunction::SetResultFromError( + int channel_id, + cast_channel::ChannelError error) { ChannelInfo channel_info; channel_info.channel_id = channel_id; channel_info.ready_state = cast_channel::READY_STATE_CLOSED; @@ -294,7 +300,7 @@ return false; } - channel_auth_ = connect_info.auth; + channel_auth_ = cast_channel::ToChannelAuthTypeInternal(connect_info.auth); ip_endpoint_.reset(ParseConnectInfo(connect_info)); return true; } @@ -308,7 +314,7 @@ if (test_socket.get()) { socket = test_socket.release(); } else { - socket = new cast_channel::CastSocketImpl( + socket = new CastSocketImpl( extension_->id(), *ip_endpoint_, channel_auth_, ExtensionsBrowserClient::Get()->GetNetLog(), base::TimeDelta::FromMilliseconds(connect_info.timeout.get() @@ -321,17 +327,16 @@ new_channel_id_ = AddSocket(base::WrapUnique(socket)); // Construct read delegates. - std::unique_ptr<api::cast_channel::CastTransport::Delegate> delegate( + std::unique_ptr<CastTransport::Delegate> delegate( base::MakeUnique<CastMessageHandler>( base::Bind(&CastChannelAPI::SendEvent, api_->AsWeakPtr(), extension_->id()), socket, api_->GetLogger())); if (socket->keep_alive()) { // Wrap read delegate in a KeepAliveDelegate for timeout handling. - api::cast_channel::KeepAliveDelegate* keep_alive = - new api::cast_channel::KeepAliveDelegate( - socket, api_->GetLogger(), std::move(delegate), ping_interval_, - liveness_timeout_); + KeepAliveDelegate* keep_alive = + new KeepAliveDelegate(socket, api_->GetLogger(), std::move(delegate), + ping_interval_, liveness_timeout_); std::unique_ptr<base::Timer> injected_timer = api_->GetInjectedTimeoutTimerForTest(); if (injected_timer) { @@ -345,19 +350,19 @@ base::Bind(&CastChannelOpenFunction::OnOpen, this)); } -void CastChannelOpenFunction::OnOpen(cast_channel::ChannelError result) { +void CastChannelOpenFunction::OnOpen(ChannelError result) { DCHECK_CURRENTLY_ON(BrowserThread::IO); VLOG(1) << "Connect finished, OnOpen invoked."; // TODO: If we failed to open the CastSocket, we may want to clean up here, // rather than relying on the extension to call close(). This can be done by // calling RemoveSocket() and api_->GetLogger()->ClearLastErrors(channel_id). - if (result != cast_channel::CHANNEL_ERROR_UNKNOWN) { + if (result != ChannelError::UNKNOWN) { CastSocket* socket = GetSocket(new_channel_id_); CHECK(socket); SetResultFromSocket(*socket); } else { // The socket is being destroyed. - SetResultFromError(new_channel_id_, result); + SetResultFromError(new_channel_id_, cast_channel::CHANNEL_ERROR_UNKNOWN); } AsyncWorkCompleted(); @@ -470,7 +475,7 @@ CastChannelOpenFunction::CastMessageHandler::CastMessageHandler( const EventDispatchCallback& ui_dispatch_cb, - cast_channel::CastSocket* socket, + CastSocket* socket, scoped_refptr<Logger> logger) : ui_dispatch_cb_(ui_dispatch_cb), socket_(socket), logger_(logger) { DCHECK(socket_); @@ -481,14 +486,14 @@ } void CastChannelOpenFunction::CastMessageHandler::OnError( - cast_channel::ChannelError error_state) { + ChannelError error_state) { DCHECK_CURRENTLY_ON(BrowserThread::IO); ChannelInfo channel_info; FillChannelInfo(*socket_, &channel_info); - channel_info.error_state = error_state; + channel_info.error_state = cast_channel::ToChannelError(error_state); ErrorInfo error_info; - FillErrorInfo(error_state, logger_->GetLastErrors(socket_->id()), + FillErrorInfo(channel_info.error_state, logger_->GetLastErrors(socket_->id()), &error_info); std::unique_ptr<base::ListValue> results = @@ -505,7 +510,7 @@ DCHECK_CURRENTLY_ON(BrowserThread::IO); MessageInfo message_info; - cast_channel::CastMessageToMessageInfo(message, &message_info); + CastMessageToMessageInfo(message, &message_info); ChannelInfo channel_info; FillChannelInfo(*socket_, &channel_info); VLOG(1) << "Received message " << ParamToString(message_info)
diff --git a/extensions/browser/api/cast_channel/cast_channel_api.h b/extensions/browser/api/cast_channel/cast_channel_api.h index d396a5d..b97faea1 100644 --- a/extensions/browser/api/cast_channel/cast_channel_api.h +++ b/extensions/browser/api/cast_channel/cast_channel_api.h
@@ -12,6 +12,8 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/threading/thread_checker.h" +#include "components/cast_channel/cast_channel_enum.h" +#include "extensions/browser/api/api_resource_manager.h" #include "extensions/browser/api/async_api_function.h" #include "extensions/browser/api/cast_channel/cast_socket.h" #include "extensions/browser/browser_context_keyed_api_factory.h" @@ -171,7 +173,7 @@ ~CastMessageHandler() override; // CastTransport::Delegate implementation. - void OnError(cast_channel::ChannelError error_state) override; + void OnError(::cast_channel::ChannelError error_state) override; void OnMessage(const cast_channel::CastMessage& message) override; void Start() override; @@ -192,14 +194,14 @@ static net::IPEndPoint* ParseConnectInfo( const cast_channel::ConnectInfo& connect_info); - void OnOpen(cast_channel::ChannelError result); + void OnOpen(::cast_channel::ChannelError result); std::unique_ptr<cast_channel::Open::Params> params_; // The id of the newly opened socket. int new_channel_id_; CastChannelAPI* api_; std::unique_ptr<net::IPEndPoint> ip_endpoint_; - cast_channel::ChannelAuthType channel_auth_; + ::cast_channel::ChannelAuthType channel_auth_; base::TimeDelta liveness_timeout_; base::TimeDelta ping_interval_;
diff --git a/extensions/browser/api/cast_channel/cast_channel_apitest.cc b/extensions/browser/api/cast_channel/cast_channel_apitest.cc index 0c5a886..13ad9133 100644 --- a/extensions/browser/api/cast_channel/cast_channel_apitest.cc +++ b/extensions/browser/api/cast_channel/cast_channel_apitest.cc
@@ -33,20 +33,20 @@ // TODO(mfoltz): Mock out the ApiResourceManager to resolve threading issues // (crbug.com/398242) and simulate unloading of the extension. -namespace cast_channel = extensions::api::cast_channel; -using cast_channel::CastMessage; -using cast_channel::CastSocket; -using cast_channel::CastTransport; -using cast_channel::ChannelAuthType; -using cast_channel::ChannelError; -using cast_channel::CreateIPEndPointForTest; -using cast_channel::ErrorInfo; -using cast_channel::LastErrors; -using cast_channel::Logger; -using cast_channel::MessageInfo; -using cast_channel::MockCastSocket; -using cast_channel::MockCastTransport; -using cast_channel::ReadyState; +using ::cast_channel::ChannelAuthType; +using ::cast_channel::ChannelError; +using ::cast_channel::ReadyState; + +using extensions::api::cast_channel::CastMessage; +using extensions::api::cast_channel::CastSocket; +using extensions::api::cast_channel::CastTransport; +using extensions::api::cast_channel::CreateIPEndPointForTest; +using extensions::api::cast_channel::ErrorInfo; +using extensions::api::cast_channel::LastErrors; +using extensions::api::cast_channel::Logger; +using extensions::api::cast_channel::MessageInfo; +using extensions::api::cast_channel::MockCastSocket; +using extensions::api::cast_channel::MockCastTransport; using extensions::Extension; namespace utils = extension_function_test_utils; @@ -89,7 +89,7 @@ ExtensionApiTest::SetUpCommandLine(command_line); command_line->AppendSwitchASCII( extensions::switches::kWhitelistedExtensionID, - cast_channel::kTestExtensionId); + extensions::api::cast_channel::kTestExtensionId); } void SetUpMockCastSocket() { @@ -108,49 +108,47 @@ ON_CALL(*mock_cast_socket_, ip_endpoint()) .WillByDefault(ReturnRef(ip_endpoint_)); ON_CALL(*mock_cast_socket_, channel_auth()) - .WillByDefault(Return(cast_channel::CHANNEL_AUTH_TYPE_SSL_VERIFIED)); + .WillByDefault(Return(ChannelAuthType::SSL_VERIFIED)); ON_CALL(*mock_cast_socket_, keep_alive()).WillByDefault(Return(false)); } void SetUpOpenSendClose() { SetUpMockCastSocket(); EXPECT_CALL(*mock_cast_socket_, error_state()) - .WillRepeatedly(Return(cast_channel::CHANNEL_ERROR_NONE)); + .WillRepeatedly(Return(ChannelError::NONE)); { InSequence sequence; EXPECT_CALL(*mock_cast_socket_, ConnectRawPtr(_, _)) - .WillOnce( - InvokeCompletionCallback<1>(cast_channel::CHANNEL_ERROR_NONE)); + .WillOnce(InvokeCompletionCallback<1>(ChannelError::NONE)); EXPECT_CALL(*mock_cast_socket_, ready_state()) - .WillOnce(Return(cast_channel::READY_STATE_OPEN)); + .WillOnce(Return(ReadyState::OPEN)); EXPECT_CALL(*mock_cast_socket_->mock_transport(), SendMessage(A<const CastMessage&>(), _)) .WillOnce(InvokeCompletionCallback<1>(net::OK)); EXPECT_CALL(*mock_cast_socket_, ready_state()) - .WillOnce(Return(cast_channel::READY_STATE_OPEN)); + .WillOnce(Return(ReadyState::OPEN)); EXPECT_CALL(*mock_cast_socket_, Close(_)) .WillOnce(InvokeCompletionCallback<0>(net::OK)); EXPECT_CALL(*mock_cast_socket_, ready_state()) - .WillOnce(Return(cast_channel::READY_STATE_CLOSED)); + .WillOnce(Return(ReadyState::CLOSED)); } } void SetUpOpenPingTimeout() { SetUpMockCastSocket(); EXPECT_CALL(*mock_cast_socket_, error_state()) - .WillRepeatedly(Return(cast_channel::CHANNEL_ERROR_NONE)); + .WillRepeatedly(Return(ChannelError::NONE)); EXPECT_CALL(*mock_cast_socket_, keep_alive()).WillRepeatedly(Return(true)); { InSequence sequence; EXPECT_CALL(*mock_cast_socket_, ConnectRawPtr(_, _)) - .WillOnce(DoAll( - SaveArg<0>(&message_delegate_), - InvokeCompletionCallback<1>(cast_channel::CHANNEL_ERROR_NONE))); + .WillOnce(DoAll(SaveArg<0>(&message_delegate_), + InvokeCompletionCallback<1>(ChannelError::NONE))); EXPECT_CALL(*mock_cast_socket_, ready_state()) - .WillOnce(Return(cast_channel::READY_STATE_OPEN)) + .WillOnce(Return(ReadyState::OPEN)) .RetiresOnSaturation(); EXPECT_CALL(*mock_cast_socket_, ready_state()) - .WillOnce(Return(cast_channel::READY_STATE_CLOSED)); + .WillOnce(Return(ReadyState::CLOSED)); } } @@ -160,10 +158,10 @@ // Logs some bogus error details and calls the OnError handler. void DoCallOnError(extensions::CastChannelAPI* api) { - api->GetLogger()->LogSocketEventWithRv(mock_cast_socket_->id(), - cast_channel::proto::SOCKET_WRITE, - net::ERR_FAILED); - message_delegate_->OnError(cast_channel::CHANNEL_ERROR_CONNECT_ERROR); + api->GetLogger()->LogSocketEventWithRv( + mock_cast_socket_->id(), + extensions::api::cast_channel::proto::SOCKET_WRITE, net::ERR_FAILED); + message_delegate_->OnError(ChannelError::CONNECT_ERROR); } protected: @@ -187,7 +185,7 @@ CHECK(message_delegate_); content::BrowserThread::PostTask( content::BrowserThread::IO, FROM_HERE, - base::Bind(&cast_channel::CastTransport::Delegate::Start, + base::Bind(&CastTransport::Delegate::Start, base::Unretained(message_delegate_))); } @@ -303,21 +301,20 @@ IN_PROC_BROWSER_TEST_F(CastChannelAPITest, MAYBE_TestOpenReceiveClose) { SetUpMockCastSocket(); EXPECT_CALL(*mock_cast_socket_, error_state()) - .WillRepeatedly(Return(cast_channel::CHANNEL_ERROR_NONE)); + .WillRepeatedly(Return(ChannelError::NONE)); { InSequence sequence; EXPECT_CALL(*mock_cast_socket_, ConnectRawPtr(NotNull(), _)) - .WillOnce(DoAll( - SaveArg<0>(&message_delegate_), - InvokeCompletionCallback<1>(cast_channel::CHANNEL_ERROR_NONE))); + .WillOnce(DoAll(SaveArg<0>(&message_delegate_), + InvokeCompletionCallback<1>(ChannelError::NONE))); EXPECT_CALL(*mock_cast_socket_, ready_state()) .Times(3) - .WillRepeatedly(Return(cast_channel::READY_STATE_OPEN)); + .WillRepeatedly(Return(ReadyState::OPEN)); EXPECT_CALL(*mock_cast_socket_, Close(_)) .WillOnce(InvokeCompletionCallback<0>(net::OK)); EXPECT_CALL(*mock_cast_socket_, ready_state()) - .WillOnce(Return(cast_channel::READY_STATE_CLOSED)); + .WillOnce(Return(ReadyState::CLOSED)); } EXPECT_TRUE(RunExtensionSubtest("cast_channel/api", @@ -341,14 +338,13 @@ SetUpMockCastSocket(); EXPECT_CALL(*mock_cast_socket_, ConnectRawPtr(NotNull(), _)) - .WillOnce(DoAll(SaveArg<0>(&message_delegate_), - InvokeDelegateOnError(this, GetApi()), - InvokeCompletionCallback<1>( - cast_channel::CHANNEL_ERROR_CONNECT_ERROR))); + .WillOnce(DoAll( + SaveArg<0>(&message_delegate_), InvokeDelegateOnError(this, GetApi()), + InvokeCompletionCallback<1>(ChannelError::CONNECT_ERROR))); EXPECT_CALL(*mock_cast_socket_, error_state()) - .WillRepeatedly(Return(cast_channel::CHANNEL_ERROR_CONNECT_ERROR)); + .WillRepeatedly(Return(ChannelError::CONNECT_ERROR)); EXPECT_CALL(*mock_cast_socket_, ready_state()) - .WillRepeatedly(Return(cast_channel::READY_STATE_CLOSED)); + .WillRepeatedly(Return(ReadyState::CLOSED)); EXPECT_CALL(*mock_cast_socket_, Close(_)) .WillOnce(InvokeCompletionCallback<0>(net::OK));
diff --git a/extensions/browser/api/cast_channel/cast_channel_enum_util.cc b/extensions/browser/api/cast_channel/cast_channel_enum_util.cc new file mode 100644 index 0000000..e3e7022 --- /dev/null +++ b/extensions/browser/api/cast_channel/cast_channel_enum_util.cc
@@ -0,0 +1,87 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/browser/api/cast_channel/cast_channel_enum_util.h" + +namespace extensions { +namespace api { +namespace cast_channel { + +api::cast_channel::ReadyState ToReadyState( + ::cast_channel::ReadyState ready_state) { + switch (ready_state) { + case ::cast_channel::ReadyState::NONE: + return READY_STATE_NONE; + case ::cast_channel::ReadyState::CONNECTING: + return READY_STATE_CONNECTING; + case ::cast_channel::ReadyState::OPEN: + return READY_STATE_OPEN; + case ::cast_channel::ReadyState::CLOSING: + return READY_STATE_CLOSING; + case ::cast_channel::ReadyState::CLOSED: + return READY_STATE_CLOSED; + } + NOTREACHED() << "Unknown ready_state " << ReadyStateToString(ready_state); + return READY_STATE_NONE; +} + +api::cast_channel::ChannelError ToChannelError( + ::cast_channel::ChannelError channel_error) { + switch (channel_error) { + case ::cast_channel::ChannelError::NONE: + return CHANNEL_ERROR_NONE; + case ::cast_channel::ChannelError::CHANNEL_NOT_OPEN: + return CHANNEL_ERROR_CHANNEL_NOT_OPEN; + case ::cast_channel::ChannelError::AUTHENTICATION_ERROR: + return CHANNEL_ERROR_AUTHENTICATION_ERROR; + case ::cast_channel::ChannelError::CONNECT_ERROR: + return CHANNEL_ERROR_CONNECT_ERROR; + case ::cast_channel::ChannelError::CAST_SOCKET_ERROR: + return CHANNEL_ERROR_SOCKET_ERROR; + case ::cast_channel::ChannelError::TRANSPORT_ERROR: + return CHANNEL_ERROR_TRANSPORT_ERROR; + case ::cast_channel::ChannelError::INVALID_MESSAGE: + return CHANNEL_ERROR_INVALID_MESSAGE; + case ::cast_channel::ChannelError::INVALID_CHANNEL_ID: + return CHANNEL_ERROR_INVALID_CHANNEL_ID; + case ::cast_channel::ChannelError::CONNECT_TIMEOUT: + return CHANNEL_ERROR_CONNECT_TIMEOUT; + case ::cast_channel::ChannelError::PING_TIMEOUT: + return CHANNEL_ERROR_PING_TIMEOUT; + case ::cast_channel::ChannelError::UNKNOWN: + return CHANNEL_ERROR_UNKNOWN; + } + NOTREACHED() << "Unknown channel_error " + << ChannelErrorToString(channel_error); + return CHANNEL_ERROR_NONE; +} + +api::cast_channel::ChannelAuthType ToChannelAuthType( + ::cast_channel::ChannelAuthType channel_auth) { + switch (channel_auth) { + case ::cast_channel::ChannelAuthType::NONE: + return CHANNEL_AUTH_TYPE_NONE; + case ::cast_channel::ChannelAuthType::SSL_VERIFIED: + return CHANNEL_AUTH_TYPE_SSL_VERIFIED; + } + NOTREACHED() << "Unknown channel_auth " + << ChannelAuthTypeToString(channel_auth); + return CHANNEL_AUTH_TYPE_NONE; +} + +::cast_channel::ChannelAuthType ToChannelAuthTypeInternal( + api::cast_channel::ChannelAuthType channel_auth) { + switch (channel_auth) { + case CHANNEL_AUTH_TYPE_NONE: + return ::cast_channel::ChannelAuthType::NONE; + case CHANNEL_AUTH_TYPE_SSL_VERIFIED: + return ::cast_channel::ChannelAuthType::SSL_VERIFIED; + } + NOTREACHED() << "Unknown channel_auth " << channel_auth; + return ::cast_channel::ChannelAuthType::NONE; +} + +} // namespace cast_channel +} // namespace api +} // namespace extensions
diff --git a/extensions/browser/api/cast_channel/cast_channel_enum_util.h b/extensions/browser/api/cast_channel/cast_channel_enum_util.h new file mode 100644 index 0000000..0fbe066 --- /dev/null +++ b/extensions/browser/api/cast_channel/cast_channel_enum_util.h
@@ -0,0 +1,28 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_BROWSER_API_CAST_CHANNEL_CAST_CHANNEL_TYPE_UTIL_H_ +#define EXTENSIONS_BROWSER_API_CAST_CHANNEL_CAST_CHANNEL_TYPE_UTIL_H_ + +#include "components/cast_channel/cast_channel_enum.h" +#include "extensions/common/api/cast_channel.h" + +namespace extensions { +namespace api { +namespace cast_channel { + +api::cast_channel::ReadyState ToReadyState( + ::cast_channel::ReadyState ready_state); +api::cast_channel::ChannelError ToChannelError( + ::cast_channel::ChannelError channel_error); +api::cast_channel::ChannelAuthType ToChannelAuthType( + ::cast_channel::ChannelAuthType channel_auth); +::cast_channel::ChannelAuthType ToChannelAuthTypeInternal( + api::cast_channel::ChannelAuthType channel_auth); + +} // namespace cast_channel +} // namespace api +} // namespace extensions + +#endif // EXTENSIONS_BROWSER_API_CAST_CHANNEL_CAST_CHANNEL_TYPE_UTIL_H_
diff --git a/extensions/browser/api/cast_channel/cast_channel_enum_util_unittest.cc b/extensions/browser/api/cast_channel/cast_channel_enum_util_unittest.cc new file mode 100644 index 0000000..a25c6898 --- /dev/null +++ b/extensions/browser/api/cast_channel/cast_channel_enum_util_unittest.cc
@@ -0,0 +1,67 @@ +// 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 "extensions/browser/api/cast_channel/cast_channel_enum_util.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace extensions { +namespace api { +namespace cast_channel { +namespace { + +TEST(CastChannelTypeUtilTest, TestToReadyState) { + EXPECT_EQ(READY_STATE_NONE, ToReadyState(::cast_channel::ReadyState::NONE)); + EXPECT_EQ(READY_STATE_CONNECTING, + ToReadyState(::cast_channel::ReadyState::CONNECTING)); + EXPECT_EQ(READY_STATE_OPEN, ToReadyState(::cast_channel::ReadyState::OPEN)); + EXPECT_EQ(READY_STATE_CLOSING, + ToReadyState(::cast_channel::ReadyState::CLOSING)); + EXPECT_EQ(READY_STATE_CLOSED, + ToReadyState(::cast_channel::ReadyState::CLOSED)); +} + +TEST(CastChannelTypeUtilTest, TestToChannelError) { + EXPECT_EQ(CHANNEL_ERROR_NONE, + ToChannelError(::cast_channel::ChannelError::NONE)); + EXPECT_EQ(CHANNEL_ERROR_CHANNEL_NOT_OPEN, + ToChannelError(::cast_channel::ChannelError::CHANNEL_NOT_OPEN)); + EXPECT_EQ(CHANNEL_ERROR_AUTHENTICATION_ERROR, + ToChannelError(::cast_channel::ChannelError::AUTHENTICATION_ERROR)); + EXPECT_EQ(CHANNEL_ERROR_CONNECT_ERROR, + ToChannelError(::cast_channel::ChannelError::CONNECT_ERROR)); + EXPECT_EQ(CHANNEL_ERROR_SOCKET_ERROR, + ToChannelError(::cast_channel::ChannelError::CAST_SOCKET_ERROR)); + EXPECT_EQ(CHANNEL_ERROR_TRANSPORT_ERROR, + ToChannelError(::cast_channel::ChannelError::TRANSPORT_ERROR)); + EXPECT_EQ(CHANNEL_ERROR_INVALID_MESSAGE, + ToChannelError(::cast_channel::ChannelError::INVALID_MESSAGE)); + EXPECT_EQ(CHANNEL_ERROR_INVALID_CHANNEL_ID, + ToChannelError(::cast_channel::ChannelError::INVALID_CHANNEL_ID)); + EXPECT_EQ(CHANNEL_ERROR_CONNECT_TIMEOUT, + ToChannelError(::cast_channel::ChannelError::CONNECT_TIMEOUT)); + EXPECT_EQ(CHANNEL_ERROR_PING_TIMEOUT, + ToChannelError(::cast_channel::ChannelError::PING_TIMEOUT)); + EXPECT_EQ(CHANNEL_ERROR_UNKNOWN, + ToChannelError(::cast_channel::ChannelError::UNKNOWN)); +} + +TEST(CastChannelTypeUtilTest, TestToChannelAuthType) { + EXPECT_EQ(CHANNEL_AUTH_TYPE_NONE, + ToChannelAuthType(::cast_channel::ChannelAuthType::NONE)); + EXPECT_EQ(CHANNEL_AUTH_TYPE_SSL_VERIFIED, + ToChannelAuthType(::cast_channel::ChannelAuthType::SSL_VERIFIED)); +} + +TEST(CastChannelTypeUtilTest, TestToChannelAuthTypeInternal) { + EXPECT_EQ(::cast_channel::ChannelAuthType::NONE, + ToChannelAuthTypeInternal(CHANNEL_AUTH_TYPE_NONE)); + EXPECT_EQ(::cast_channel::ChannelAuthType::SSL_VERIFIED, + ToChannelAuthTypeInternal(CHANNEL_AUTH_TYPE_SSL_VERIFIED)); +} + +} // namespace +} // namespace cast_channel +} // namespace api +} // namespace extensions
diff --git a/extensions/browser/api/cast_channel/cast_framer.cc b/extensions/browser/api/cast_channel/cast_framer.cc index e453415..0bd744fa 100644 --- a/extensions/browser/api/cast_channel/cast_framer.cc +++ b/extensions/browser/api/cast_channel/cast_framer.cc
@@ -119,7 +119,7 @@ DCHECK(error); DCHECK(message_length); if (error_) { - *error = CHANNEL_ERROR_INVALID_MESSAGE; + *error = ChannelError::INVALID_MESSAGE; return nullptr; } @@ -127,7 +127,7 @@ input_buffer_->offset()); CHECK_LE(num_bytes, BytesRequested()); message_bytes_received_ += num_bytes; - *error = CHANNEL_ERROR_NONE; + *error = ChannelError::NONE; *message_length = 0; switch (current_element_) { case HEADER: @@ -136,7 +136,7 @@ MessageHeader::Deserialize(input_buffer_->StartOfBuffer(), &header); if (header.message_size > MessageHeader::max_message_size()) { VLOG(1) << "Error parsing header (message size too large)."; - *error = CHANNEL_ERROR_INVALID_MESSAGE; + *error = ChannelError::INVALID_MESSAGE; error_ = true; return nullptr; } @@ -151,7 +151,7 @@ input_buffer_->StartOfBuffer() + MessageHeader::header_size(), body_size_)) { VLOG(1) << "Error parsing packet body."; - *error = CHANNEL_ERROR_INVALID_MESSAGE; + *error = ChannelError::INVALID_MESSAGE; error_ = true; return nullptr; }
diff --git a/extensions/browser/api/cast_channel/cast_framer.h b/extensions/browser/api/cast_channel/cast_framer.h index ec8fcfe6..8a5b6b5 100644 --- a/extensions/browser/api/cast_channel/cast_framer.h +++ b/extensions/browser/api/cast_channel/cast_framer.h
@@ -12,7 +12,7 @@ #include <string> #include "base/macros.h" -#include "extensions/common/api/cast_channel.h" +#include "components/cast_channel/cast_channel_enum.h" #include "net/base/io_buffer.h" namespace extensions { @@ -23,6 +23,8 @@ // Class for constructing and parsing CastMessage packet data. class MessageFramer { public: + using ChannelError = ::cast_channel::ChannelError; + // |input_buffer|: The input buffer used by all socket read operations that // feed data into the framer. explicit MessageFramer(scoped_refptr<net::GrowableIOBuffer> input_buffer);
diff --git a/extensions/browser/api/cast_channel/cast_framer_unittest.cc b/extensions/browser/api/cast_channel/cast_framer_unittest.cc index 4000e1a..87c76e4 100644 --- a/extensions/browser/api/cast_channel/cast_framer_unittest.cc +++ b/extensions/browser/api/cast_channel/cast_framer_unittest.cc
@@ -15,6 +15,9 @@ namespace extensions { namespace api { namespace cast_channel { + +using ::cast_channel::ChannelError; + class CastFramerTest : public testing::Test { public: CastFramerTest() {} @@ -54,13 +57,13 @@ // Receive 1 byte of the header, framer demands 3 more bytes. EXPECT_EQ(4u, framer_->BytesRequested()); EXPECT_EQ(nullptr, framer_->Ingest(1, &message_length, &error).get()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_NONE, error); + EXPECT_EQ(ChannelError::NONE, error); EXPECT_EQ(3u, framer_->BytesRequested()); // Ingest remaining 3, expect that the framer has moved on to requesting the // body contents. EXPECT_EQ(nullptr, framer_->Ingest(3, &message_length, &error).get()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_NONE, error); + EXPECT_EQ(ChannelError::NONE, error); EXPECT_EQ( cast_message_str_.size() - MessageFramer::MessageHeader::header_size(), framer_->BytesRequested()); @@ -69,7 +72,7 @@ std::unique_ptr<CastMessage> message; message = framer_->Ingest(framer_->BytesRequested(), &message_length, &error); EXPECT_NE(static_cast<CastMessage*>(nullptr), message.get()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_NONE, error); + EXPECT_EQ(ChannelError::NONE, error); EXPECT_EQ(message->SerializeAsString(), cast_message_.SerializeAsString()); EXPECT_EQ(4u, framer_->BytesRequested()); EXPECT_EQ(message->SerializeAsString().size(), message_length); @@ -97,14 +100,14 @@ ChannelError error; EXPECT_EQ(4u, framer_->BytesRequested()); EXPECT_EQ(nullptr, framer_->Ingest(4, &bytes_ingested, &error).get()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_INVALID_MESSAGE, error); + EXPECT_EQ(ChannelError::INVALID_MESSAGE, error); EXPECT_EQ(0u, framer_->BytesRequested()); // Test that the parser enters a terminal error state. WriteToBuffer(cast_message_str_); EXPECT_EQ(0u, framer_->BytesRequested()); EXPECT_EQ(nullptr, framer_->Ingest(4, &bytes_ingested, &error).get()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_INVALID_MESSAGE, error); + EXPECT_EQ(ChannelError::INVALID_MESSAGE, error); EXPECT_EQ(0u, framer_->BytesRequested()); } @@ -126,14 +129,14 @@ ChannelError error; EXPECT_EQ(4u, framer_->BytesRequested()); EXPECT_EQ(nullptr, framer_->Ingest(4, &message_length, &error).get()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_NONE, error); + EXPECT_EQ(ChannelError::NONE, error); EXPECT_EQ(cast_message_str_.size() - 4, framer_->BytesRequested()); // Send body, expect an error. std::unique_ptr<CastMessage> message; EXPECT_EQ(nullptr, framer_->Ingest(framer_->BytesRequested(), &message_length, &error).get()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_INVALID_MESSAGE, error); + EXPECT_EQ(ChannelError::INVALID_MESSAGE, error); } } // namespace cast_channel } // namespace api
diff --git a/extensions/browser/api/cast_channel/cast_socket.cc b/extensions/browser/api/cast_channel/cast_socket.cc index be7292e..cb258625 100644 --- a/extensions/browser/api/cast_channel/cast_socket.cc +++ b/extensions/browser/api/cast_channel/cast_socket.cc
@@ -50,8 +50,10 @@ // Helper for logging data with remote host IP and authentication state. // Assumes |ip_endpoint_| of type net::IPEndPoint and |channel_auth_| of enum // type ChannelAuthType are available in the current scope. -#define CONNECTION_INFO() \ - "[" << ip_endpoint_.ToString() << ", auth=" << channel_auth_ << "] " +#define CONNECTION_INFO() \ + "[" << ip_endpoint_.ToString() \ + << ", auth=" << ::cast_channel::ChannelAuthTypeToString(channel_auth_) \ + << "] " #define VLOG_WITH_CONNECTION(level) VLOG(level) << CONNECTION_INFO() #define LOG_WITH_CONNECTION(level) LOG(level) << CONNECTION_INFO() @@ -85,6 +87,10 @@ } // namespace +using ChannelError = ::cast_channel::ChannelError; +using ChannelAuthType = ::cast_channel::ChannelAuthType; +using ReadyState = ::cast_channel::ReadyState; + CastSocketImpl::CastSocketImpl(const std::string& owner_extension_id, const net::IPEndPoint& ip_endpoint, ChannelAuthType channel_auth, @@ -125,8 +131,8 @@ device_capabilities_(device_capabilities), audio_only_(false), connect_state_(proto::CONN_STATE_START_CONNECT), - error_state_(CHANNEL_ERROR_NONE), - ready_state_(READY_STATE_NONE), + error_state_(ChannelError::NONE), + ready_state_(ReadyState::NONE), auth_delegate_(nullptr) { DCHECK(net_log_); net_log_source_.type = net::NetLogSourceType::SOCKET; @@ -139,7 +145,7 @@ CloseInternal(); if (!connect_callback_.is_null()) - base::ResetAndReturn(&connect_callback_).Run(CHANNEL_ERROR_UNKNOWN); + base::ResetAndReturn(&connect_callback_).Run(ChannelError::UNKNOWN); } ReadyState CastSocketImpl::ready_state() const { @@ -249,18 +255,19 @@ void CastSocketImpl::Connect(std::unique_ptr<CastTransport::Delegate> delegate, base::Callback<void(ChannelError)> callback) { DCHECK(CalledOnValidThread()); - VLOG_WITH_CONNECTION(1) << "Connect readyState = " << ready_state_; + VLOG_WITH_CONNECTION(1) << "Connect readyState = " + << ::cast_channel::ReadyStateToString(ready_state_); DCHECK_EQ(proto::CONN_STATE_START_CONNECT, connect_state_); delegate_ = std::move(delegate); - if (ready_state_ != READY_STATE_NONE) { - callback.Run(CHANNEL_ERROR_CONNECT_ERROR); + if (ready_state_ != ReadyState::NONE) { + callback.Run(ChannelError::CONNECT_ERROR); return; } connect_callback_ = callback; - SetReadyState(READY_STATE_CONNECTING); + SetReadyState(ReadyState::CONNECTING); SetConnectState(proto::CONN_STATE_TCP_CONNECT); // Set up connection timeout. @@ -285,7 +292,7 @@ // Stop all pending connection setup tasks and report back to the client. is_canceled_ = true; VLOG_WITH_CONNECTION(1) << "Timeout while establishing a connection."; - SetErrorState(CHANNEL_ERROR_CONNECT_TIMEOUT); + SetErrorState(ChannelError::CONNECT_TIMEOUT); DoConnectCallback(); } @@ -349,7 +356,7 @@ default: NOTREACHED() << "Unknown state in connect flow: " << state; SetConnectState(proto::CONN_STATE_FINISHED); - SetErrorState(CHANNEL_ERROR_UNKNOWN); + SetErrorState(ChannelError::UNKNOWN); DoConnectCallback(); return; } @@ -386,10 +393,10 @@ SetConnectState(proto::CONN_STATE_SSL_CONNECT); } else if (connect_result == net::ERR_CONNECTION_TIMED_OUT) { SetConnectState(proto::CONN_STATE_FINISHED); - SetErrorState(CHANNEL_ERROR_CONNECT_TIMEOUT); + SetErrorState(ChannelError::CONNECT_TIMEOUT); } else { SetConnectState(proto::CONN_STATE_FINISHED); - SetErrorState(CHANNEL_ERROR_CONNECT_ERROR); + SetErrorState(ChannelError::CONNECT_ERROR); } return connect_result; } @@ -416,7 +423,7 @@ if (!peer_cert_) { LOG_WITH_CONNECTION(WARNING) << "Could not extract peer cert."; SetConnectState(proto::CONN_STATE_FINISHED); - SetErrorState(CHANNEL_ERROR_AUTHENTICATION_ERROR); + SetErrorState(ChannelError::AUTHENTICATION_ERROR); return net::ERR_CERT_INVALID; } @@ -433,10 +440,10 @@ SetConnectState(proto::CONN_STATE_AUTH_CHALLENGE_SEND); } else if (result == net::ERR_CONNECTION_TIMED_OUT) { SetConnectState(proto::CONN_STATE_FINISHED); - SetErrorState(CHANNEL_ERROR_CONNECT_TIMEOUT); + SetErrorState(ChannelError::CONNECT_TIMEOUT); } else { SetConnectState(proto::CONN_STATE_FINISHED); - SetErrorState(CHANNEL_ERROR_AUTHENTICATION_ERROR); + SetErrorState(ChannelError::AUTHENTICATION_ERROR); } return result; } @@ -461,7 +468,7 @@ VLOG_WITH_CONNECTION(1) << "DoAuthChallengeSendComplete: " << result; if (result < 0) { SetConnectState(proto::CONN_STATE_ERROR); - SetErrorState(CHANNEL_ERROR_SOCKET_ERROR); + SetErrorState(ChannelError::CAST_SOCKET_ERROR); logger_->LogSocketEventWithRv(channel_id_, proto::SEND_AUTH_CHALLENGE_FAILED, result); return result; @@ -473,7 +480,7 @@ CastSocketImpl::AuthTransportDelegate::AuthTransportDelegate( CastSocketImpl* socket) - : socket_(socket), error_state_(CHANNEL_ERROR_NONE) { + : socket_(socket), error_state_(ChannelError::NONE) { DCHECK(socket); } @@ -493,7 +500,7 @@ void CastSocketImpl::AuthTransportDelegate::OnMessage( const CastMessage& message) { if (!IsAuthMessage(message)) { - error_state_ = CHANNEL_ERROR_TRANSPORT_ERROR; + error_state_ = ChannelError::TRANSPORT_ERROR; socket_->PostTaskToStartConnectLoop(net::ERR_INVALID_RESPONSE); } else { socket_->challenge_reply_.reset(new CastMessage(message)); @@ -507,7 +514,7 @@ int CastSocketImpl::DoAuthChallengeReplyComplete(int result) { VLOG_WITH_CONNECTION(1) << "DoAuthChallengeReplyComplete: " << result; - if (auth_delegate_->error_state() != CHANNEL_ERROR_NONE) { + if (auth_delegate_->error_state() != ChannelError::NONE) { SetErrorState(auth_delegate_->error_state()); SetConnectState(proto::CONN_STATE_ERROR); return net::ERR_CONNECTION_FAILED; @@ -520,7 +527,7 @@ } if (!VerifyChallengeReply()) { - SetErrorState(CHANNEL_ERROR_AUTHENTICATION_ERROR); + SetErrorState(ChannelError::AUTHENTICATION_ERROR); SetConnectState(proto::CONN_STATE_ERROR); return net::ERR_CONNECTION_FAILED; } @@ -531,14 +538,15 @@ } void CastSocketImpl::DoConnectCallback() { - VLOG(1) << "DoConnectCallback (error_state = " << error_state_ << ")"; + VLOG(1) << "DoConnectCallback (error_state = " + << ::cast_channel::ChannelErrorToString(error_state_) << ")"; if (connect_callback_.is_null()) { DLOG(FATAL) << "Connection callback invoked multiple times."; return; } - if (error_state_ == CHANNEL_ERROR_NONE) { - SetReadyState(READY_STATE_OPEN); + if (error_state_ == ChannelError::NONE) { + SetReadyState(ReadyState::OPEN); transport_->SetReadDelegate(std::move(delegate_)); } else { CloseInternal(); @@ -558,11 +566,12 @@ // TODO(mfoltz): Enforce this when CastChannelAPITest is rewritten to create // and free sockets on the same thread. crbug.com/398242 DCHECK(CalledOnValidThread()); - if (ready_state_ == READY_STATE_CLOSED) { + if (ready_state_ == ReadyState::CLOSED) { return; } - VLOG_WITH_CONNECTION(1) << "Close ReadyState = " << ready_state_; + VLOG_WITH_CONNECTION(1) << "Close ReadyState = " + << ::cast_channel::ReadyStateToString(ready_state_); transport_.reset(); tcp_socket_.reset(); socket_.reset(); @@ -575,7 +584,7 @@ // loops. connect_loop_callback_.Cancel(); connect_timeout_callback_.Cancel(); - SetReadyState(READY_STATE_CLOSED); + SetReadyState(ReadyState::CLOSED); } bool CastSocketImpl::CalledOnValidThread() const { @@ -598,8 +607,9 @@ } void CastSocketImpl::SetErrorState(ChannelError error_state) { - VLOG_WITH_CONNECTION(1) << "SetErrorState " << error_state; - DCHECK_EQ(CHANNEL_ERROR_NONE, error_state_); + VLOG_WITH_CONNECTION(1) << "SetErrorState " + << ::cast_channel::ChannelErrorToString(error_state); + DCHECK_EQ(ChannelError::NONE, error_state_); error_state_ = error_state; delegate_->OnError(error_state_); }
diff --git a/extensions/browser/api/cast_channel/cast_socket.h b/extensions/browser/api/cast_channel/cast_socket.h index 4ee3683..242508f 100644 --- a/extensions/browser/api/cast_channel/cast_socket.h +++ b/extensions/browser/api/cast_channel/cast_socket.h
@@ -16,10 +16,12 @@ #include "base/memory/ref_counted.h" #include "base/threading/thread_checker.h" #include "base/timer/timer.h" +#include "components/cast_channel/cast_channel_enum.h" +#include "extensions/browser/api/api_resource.h" +#include "extensions/browser/api/api_resource_manager.h" #include "extensions/browser/api/cast_channel/cast_auth_util.h" #include "extensions/browser/api/cast_channel/cast_socket.h" #include "extensions/browser/api/cast_channel/cast_transport.h" -#include "extensions/common/api/cast_channel.h" #include "extensions/common/api/cast_channel/logging.pb.h" #include "net/base/completion_callback.h" #include "net/base/io_buffer.h" @@ -58,8 +60,15 @@ // Public interface of the CastSocket class. class CastSocket { public: + using ChannelError = ::cast_channel::ChannelError; + using ChannelAuthType = ::cast_channel::ChannelAuthType; + using ReadyState = ::cast_channel::ReadyState; + virtual ~CastSocket() {} + // Used by BrowserContextKeyedAPIFactory. + static const char* service_name() { return "CastSocketImplManager"; } + // Connects the channel to the peer. If successful, the channel will be in // READY_STATE_OPEN. DO NOT delete the CastSocket object in |callback|. // Instead use Close().
diff --git a/extensions/browser/api/cast_channel/cast_socket_unittest.cc b/extensions/browser/api/cast_channel/cast_socket_unittest.cc index 29fbf778..bbd4767 100644 --- a/extensions/browser/api/cast_channel/cast_socket_unittest.cc +++ b/extensions/browser/api/cast_channel/cast_socket_unittest.cc
@@ -42,6 +42,9 @@ const int64_t kDistantTimeoutMillis = 100000; // 100 seconds (never hit). +using ::cast_channel::ChannelError; +using ::cast_channel::ChannelAuthType; +using ::cast_channel::ReadyState; using ::testing::_; using ::testing::A; using ::testing::DoAll; @@ -177,7 +180,7 @@ Logger* logger, uint64_t device_capabilities = cast_channel::CastDeviceCapability::NONE) { return std::unique_ptr<TestCastSocket>(new TestCastSocket( - CreateIPEndPointForTest(), CHANNEL_AUTH_TYPE_SSL_VERIFIED, + CreateIPEndPointForTest(), ChannelAuthType::SSL_VERIFIED, kDistantTimeoutMillis, logger, device_capabilities)); } @@ -372,7 +375,7 @@ SendMessage(EqualsProto(challenge_proto), _)) .WillOnce(PostCompletionCallbackTask<1>(net::OK)); EXPECT_CALL(*socket_->GetMockTransport(), Start()); - EXPECT_CALL(handler_, OnConnectComplete(CHANNEL_ERROR_NONE)); + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::NONE)); socket_->Connect(std::move(delegate_), base::Bind(&CompleteHandler::OnConnectComplete, base::Unretained(&handler_))); @@ -413,8 +416,8 @@ HandleAuthHandshake(); - EXPECT_EQ(cast_channel::READY_STATE_OPEN, socket_->ready_state()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_NONE, socket_->error_state()); + EXPECT_EQ(ReadyState::OPEN, socket_->ready_state()); + EXPECT_EQ(ChannelError::NONE, socket_->error_state()); } // Tests that the following connection flow works: @@ -431,8 +434,8 @@ HandleAuthHandshake(); - EXPECT_EQ(cast_channel::READY_STATE_OPEN, socket_->ready_state()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_NONE, socket_->error_state()); + EXPECT_EQ(ReadyState::OPEN, socket_->ready_state()); + EXPECT_EQ(ChannelError::NONE, socket_->error_state()); } // Test that an AuthMessage with a mangled namespace triggers cancelation @@ -449,7 +452,7 @@ SendMessage(EqualsProto(challenge_proto), _)) .WillOnce(PostCompletionCallbackTask<1>(net::OK)); EXPECT_CALL(*socket_->GetMockTransport(), Start()); - EXPECT_CALL(handler_, OnConnectComplete(CHANNEL_ERROR_TRANSPORT_ERROR)); + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::TRANSPORT_ERROR)); socket_->Connect(std::move(delegate_), base::Bind(&CompleteHandler::OnConnectComplete, base::Unretained(&handler_))); @@ -461,9 +464,8 @@ mangled_auth_reply); RunPendingTasks(); - EXPECT_EQ(cast_channel::READY_STATE_CLOSED, socket_->ready_state()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_TRANSPORT_ERROR, - socket_->error_state()); + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state()); + EXPECT_EQ(ChannelError::TRANSPORT_ERROR, socket_->error_state()); // Verifies that the CastSocket's resources were torn down during channel // close. (see http://crbug.com/504078) @@ -476,14 +478,14 @@ socket_->SetupTcpConnect(net::ASYNC, net::ERR_FAILED); - EXPECT_CALL(handler_, OnConnectComplete(CHANNEL_ERROR_CONNECT_ERROR)); + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::CONNECT_ERROR)); socket_->Connect(std::move(delegate_), base::Bind(&CompleteHandler::OnConnectComplete, base::Unretained(&handler_))); RunPendingTasks(); - EXPECT_EQ(cast_channel::READY_STATE_CLOSED, socket_->ready_state()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_CONNECT_ERROR, socket_->error_state()); + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state()); + EXPECT_EQ(ChannelError::CONNECT_ERROR, socket_->error_state()); } // Test connection error - TCP connect fails (sync) @@ -492,51 +494,49 @@ socket_->SetupTcpConnect(net::SYNCHRONOUS, net::ERR_FAILED); - EXPECT_CALL(handler_, OnConnectComplete(CHANNEL_ERROR_CONNECT_ERROR)); + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::CONNECT_ERROR)); socket_->Connect(std::move(delegate_), base::Bind(&CompleteHandler::OnConnectComplete, base::Unretained(&handler_))); RunPendingTasks(); - EXPECT_EQ(cast_channel::READY_STATE_CLOSED, socket_->ready_state()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_CONNECT_ERROR, socket_->error_state()); + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state()); + EXPECT_EQ(ChannelError::CONNECT_ERROR, socket_->error_state()); } // Test connection error - timeout TEST_F(CastSocketTest, TestConnectTcpTimeoutError) { CreateCastSocketSecure(); socket_->SetupTcpConnectUnresponsive(); - EXPECT_CALL(handler_, OnConnectComplete(CHANNEL_ERROR_CONNECT_TIMEOUT)); - EXPECT_CALL(*delegate_, OnError(CHANNEL_ERROR_CONNECT_TIMEOUT)); + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::CONNECT_TIMEOUT)); + EXPECT_CALL(*delegate_, OnError(ChannelError::CONNECT_TIMEOUT)); socket_->Connect(std::move(delegate_), base::Bind(&CompleteHandler::OnConnectComplete, base::Unretained(&handler_))); RunPendingTasks(); - EXPECT_EQ(cast_channel::READY_STATE_CONNECTING, socket_->ready_state()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_NONE, socket_->error_state()); + EXPECT_EQ(ReadyState::CONNECTING, socket_->ready_state()); + EXPECT_EQ(ChannelError::NONE, socket_->error_state()); socket_->TriggerTimeout(); RunPendingTasks(); - EXPECT_EQ(cast_channel::READY_STATE_CLOSED, socket_->ready_state()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_CONNECT_TIMEOUT, - socket_->error_state()); + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state()); + EXPECT_EQ(ChannelError::CONNECT_TIMEOUT, socket_->error_state()); } // Test connection error - TCP socket returns timeout TEST_F(CastSocketTest, TestConnectTcpSocketTimeoutError) { CreateCastSocketSecure(); socket_->SetupTcpConnect(net::SYNCHRONOUS, net::ERR_CONNECTION_TIMED_OUT); - EXPECT_CALL(handler_, OnConnectComplete(CHANNEL_ERROR_CONNECT_TIMEOUT)); - EXPECT_CALL(*delegate_, OnError(CHANNEL_ERROR_CONNECT_TIMEOUT)); + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::CONNECT_TIMEOUT)); + EXPECT_CALL(*delegate_, OnError(ChannelError::CONNECT_TIMEOUT)); socket_->Connect(std::move(delegate_), base::Bind(&CompleteHandler::OnConnectComplete, base::Unretained(&handler_))); RunPendingTasks(); - EXPECT_EQ(cast_channel::READY_STATE_CLOSED, socket_->ready_state()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_CONNECT_TIMEOUT, - socket_->error_state()); + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state()); + EXPECT_EQ(ChannelError::CONNECT_TIMEOUT, socket_->error_state()); EXPECT_EQ(net::ERR_CONNECTION_TIMED_OUT, logger_->GetLastErrors(socket_->id()).net_return_value); } @@ -548,15 +548,14 @@ socket_->SetupTcpConnect(net::SYNCHRONOUS, net::OK); socket_->SetupSslConnect(net::SYNCHRONOUS, net::ERR_FAILED); - EXPECT_CALL(handler_, OnConnectComplete(CHANNEL_ERROR_AUTHENTICATION_ERROR)); + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::AUTHENTICATION_ERROR)); socket_->Connect(std::move(delegate_), base::Bind(&CompleteHandler::OnConnectComplete, base::Unretained(&handler_))); RunPendingTasks(); - EXPECT_EQ(cast_channel::READY_STATE_CLOSED, socket_->ready_state()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_AUTHENTICATION_ERROR, - socket_->error_state()); + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state()); + EXPECT_EQ(ChannelError::AUTHENTICATION_ERROR, socket_->error_state()); } // Test connection error - SSL connect fails (sync) @@ -566,15 +565,14 @@ socket_->SetupTcpConnect(net::SYNCHRONOUS, net::OK); socket_->SetupSslConnect(net::SYNCHRONOUS, net::ERR_FAILED); - EXPECT_CALL(handler_, OnConnectComplete(CHANNEL_ERROR_AUTHENTICATION_ERROR)); + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::AUTHENTICATION_ERROR)); socket_->Connect(std::move(delegate_), base::Bind(&CompleteHandler::OnConnectComplete, base::Unretained(&handler_))); RunPendingTasks(); - EXPECT_EQ(cast_channel::READY_STATE_CLOSED, socket_->ready_state()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_AUTHENTICATION_ERROR, - socket_->error_state()); + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state()); + EXPECT_EQ(ChannelError::AUTHENTICATION_ERROR, socket_->error_state()); EXPECT_EQ(net::ERR_FAILED, logger_->GetLastErrors(socket_->id()).net_return_value); } @@ -586,15 +584,14 @@ socket_->SetupTcpConnect(net::SYNCHRONOUS, net::OK); socket_->SetupSslConnect(net::SYNCHRONOUS, net::ERR_CONNECTION_TIMED_OUT); - EXPECT_CALL(handler_, OnConnectComplete(CHANNEL_ERROR_CONNECT_TIMEOUT)); + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::CONNECT_TIMEOUT)); socket_->Connect(std::move(delegate_), base::Bind(&CompleteHandler::OnConnectComplete, base::Unretained(&handler_))); RunPendingTasks(); - EXPECT_EQ(cast_channel::READY_STATE_CLOSED, socket_->ready_state()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_CONNECT_TIMEOUT, - socket_->error_state()); + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state()); + EXPECT_EQ(ChannelError::CONNECT_TIMEOUT, socket_->error_state()); EXPECT_EQ(net::ERR_CONNECTION_TIMED_OUT, logger_->GetLastErrors(socket_->id()).net_return_value); } @@ -606,15 +603,14 @@ socket_->SetupTcpConnect(net::ASYNC, net::OK); socket_->SetupSslConnect(net::ASYNC, net::ERR_CONNECTION_TIMED_OUT); - EXPECT_CALL(handler_, OnConnectComplete(CHANNEL_ERROR_CONNECT_TIMEOUT)); + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::CONNECT_TIMEOUT)); socket_->Connect(std::move(delegate_), base::Bind(&CompleteHandler::OnConnectComplete, base::Unretained(&handler_))); RunPendingTasks(); - EXPECT_EQ(cast_channel::READY_STATE_CLOSED, socket_->ready_state()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_CONNECT_TIMEOUT, - socket_->error_state()); + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state()); + EXPECT_EQ(ChannelError::CONNECT_TIMEOUT, socket_->error_state()); } // Test connection error - challenge send fails @@ -628,14 +624,14 @@ SendMessage(EqualsProto(CreateAuthChallenge()), _)) .WillOnce(PostCompletionCallbackTask<1>(net::ERR_CONNECTION_RESET)); - EXPECT_CALL(handler_, OnConnectComplete(CHANNEL_ERROR_SOCKET_ERROR)); + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::CAST_SOCKET_ERROR)); socket_->Connect(std::move(delegate_), base::Bind(&CompleteHandler::OnConnectComplete, base::Unretained(&handler_))); RunPendingTasks(); - EXPECT_EQ(cast_channel::READY_STATE_CLOSED, socket_->ready_state()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_SOCKET_ERROR, socket_->error_state()); + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state()); + EXPECT_EQ(ChannelError::CAST_SOCKET_ERROR, socket_->error_state()); } // Test connection error - connection is destroyed after the challenge is @@ -666,19 +662,19 @@ SendMessage(EqualsProto(CreateAuthChallenge()), _)) .WillOnce(PostCompletionCallbackTask<1>(net::OK)); socket_->AddReadResult(net::SYNCHRONOUS, net::ERR_FAILED); - EXPECT_CALL(*delegate_, OnError(CHANNEL_ERROR_SOCKET_ERROR)); - EXPECT_CALL(handler_, OnConnectComplete(CHANNEL_ERROR_SOCKET_ERROR)); + EXPECT_CALL(*delegate_, OnError(ChannelError::CAST_SOCKET_ERROR)); + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::CAST_SOCKET_ERROR)); EXPECT_CALL(*socket_->GetMockTransport(), Start()); socket_->Connect(std::move(delegate_), base::Bind(&CompleteHandler::OnConnectComplete, base::Unretained(&handler_))); RunPendingTasks(); socket_->GetMockTransport()->current_delegate()->OnError( - CHANNEL_ERROR_SOCKET_ERROR); + ChannelError::CAST_SOCKET_ERROR); RunPendingTasks(); - EXPECT_EQ(cast_channel::READY_STATE_CLOSED, socket_->ready_state()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_SOCKET_ERROR, socket_->error_state()); + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state()); + EXPECT_EQ(ChannelError::CAST_SOCKET_ERROR, socket_->error_state()); } TEST_F(CastSocketTest, TestConnectChallengeVerificationFails) { @@ -688,12 +684,12 @@ socket_->SetupSslConnect(net::ASYNC, net::OK); socket_->SetVerifyChallengeResult(false); - EXPECT_CALL(*delegate_, OnError(CHANNEL_ERROR_AUTHENTICATION_ERROR)); + EXPECT_CALL(*delegate_, OnError(ChannelError::AUTHENTICATION_ERROR)); CastMessage challenge_proto = CreateAuthChallenge(); EXPECT_CALL(*socket_->GetMockTransport(), SendMessage(EqualsProto(challenge_proto), _)) .WillOnce(PostCompletionCallbackTask<1>(net::OK)); - EXPECT_CALL(handler_, OnConnectComplete(CHANNEL_ERROR_AUTHENTICATION_ERROR)); + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::AUTHENTICATION_ERROR)); EXPECT_CALL(*socket_->GetMockTransport(), Start()); socket_->Connect(std::move(delegate_), base::Bind(&CompleteHandler::OnConnectComplete, @@ -702,9 +698,8 @@ socket_->GetMockTransport()->current_delegate()->OnMessage(CreateAuthReply()); RunPendingTasks(); - EXPECT_EQ(cast_channel::READY_STATE_CLOSED, socket_->ready_state()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_AUTHENTICATION_ERROR, - socket_->error_state()); + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state()); + EXPECT_EQ(ChannelError::AUTHENTICATION_ERROR, socket_->error_state()); } // Sends message data through an actual non-mocked CastTransport object, @@ -732,13 +727,13 @@ EXPECT_TRUE(MessageFramer::Serialize(test_message, &test_message_str)); socket_->AddWriteResultForData(net::ASYNC, test_message_str); - EXPECT_CALL(handler_, OnConnectComplete(CHANNEL_ERROR_NONE)); + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::NONE)); socket_->Connect(std::move(delegate_), base::Bind(&CompleteHandler::OnConnectComplete, base::Unretained(&handler_))); RunPendingTasks(); - EXPECT_EQ(cast_channel::READY_STATE_OPEN, socket_->ready_state()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_NONE, socket_->error_state()); + EXPECT_EQ(ReadyState::OPEN, socket_->ready_state()); + EXPECT_EQ(ChannelError::NONE, socket_->error_state()); // Send the test message through a real transport object. EXPECT_CALL(handler_, OnWriteComplete(net::OK)); @@ -747,8 +742,8 @@ base::Unretained(&handler_))); RunPendingTasks(); - EXPECT_EQ(cast_channel::READY_STATE_OPEN, socket_->ready_state()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_NONE, socket_->error_state()); + EXPECT_EQ(ReadyState::OPEN, socket_->ready_state()); + EXPECT_EQ(ChannelError::NONE, socket_->error_state()); } // Same as TestConnectEndToEndWithRealTransportAsync, except synchronous. @@ -775,13 +770,13 @@ EXPECT_TRUE(MessageFramer::Serialize(test_message, &test_message_str)); socket_->AddWriteResultForData(net::SYNCHRONOUS, test_message_str); - EXPECT_CALL(handler_, OnConnectComplete(CHANNEL_ERROR_NONE)); + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::NONE)); socket_->Connect(std::move(delegate_), base::Bind(&CompleteHandler::OnConnectComplete, base::Unretained(&handler_))); RunPendingTasks(); - EXPECT_EQ(cast_channel::READY_STATE_OPEN, socket_->ready_state()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_NONE, socket_->error_state()); + EXPECT_EQ(ReadyState::OPEN, socket_->ready_state()); + EXPECT_EQ(ChannelError::NONE, socket_->error_state()); // Send the test message through a real transport object. EXPECT_CALL(handler_, OnWriteComplete(net::OK)); @@ -790,8 +785,8 @@ base::Unretained(&handler_))); RunPendingTasks(); - EXPECT_EQ(cast_channel::READY_STATE_OPEN, socket_->ready_state()); - EXPECT_EQ(cast_channel::CHANNEL_ERROR_NONE, socket_->error_state()); + EXPECT_EQ(ReadyState::OPEN, socket_->ready_state()); + EXPECT_EQ(ChannelError::NONE, socket_->error_state()); } } // namespace cast_channel
diff --git a/extensions/browser/api/cast_channel/cast_transport.cc b/extensions/browser/api/cast_channel/cast_transport.cc index c8805bc..12168f4 100644 --- a/extensions/browser/api/cast_channel/cast_transport.cc +++ b/extensions/browser/api/cast_channel/cast_transport.cc
@@ -24,8 +24,9 @@ #include "net/base/net_errors.h" #include "net/socket/socket.h" -#define VLOG_WITH_CONNECTION(level) \ - VLOG(level) << "[" << ip_endpoint_.ToString() << ", auth=" << channel_auth_ \ +#define VLOG_WITH_CONNECTION(level) \ + VLOG(level) << "[" << ip_endpoint_.ToString() << ", auth=" \ + << ::cast_channel::ChannelAuthTypeToString(channel_auth_) \ << "] " namespace extensions { @@ -41,7 +42,7 @@ socket_(socket), write_state_(WRITE_STATE_IDLE), read_state_(READ_STATE_READ), - error_state_(CHANNEL_ERROR_NONE), + error_state_(ChannelError::NONE), channel_id_(channel_id), ip_endpoint_(ip_endpoint), channel_auth_(channel_auth), @@ -119,25 +120,25 @@ // static proto::ErrorState CastTransportImpl::ErrorStateToProto(ChannelError state) { switch (state) { - case CHANNEL_ERROR_NONE: + case ChannelError::NONE: return proto::CHANNEL_ERROR_NONE; - case CHANNEL_ERROR_CHANNEL_NOT_OPEN: + case ChannelError::CHANNEL_NOT_OPEN: return proto::CHANNEL_ERROR_CHANNEL_NOT_OPEN; - case CHANNEL_ERROR_AUTHENTICATION_ERROR: + case ChannelError::AUTHENTICATION_ERROR: return proto::CHANNEL_ERROR_AUTHENTICATION_ERROR; - case CHANNEL_ERROR_CONNECT_ERROR: + case ChannelError::CONNECT_ERROR: return proto::CHANNEL_ERROR_CONNECT_ERROR; - case CHANNEL_ERROR_SOCKET_ERROR: + case ChannelError::CAST_SOCKET_ERROR: return proto::CHANNEL_ERROR_SOCKET_ERROR; - case CHANNEL_ERROR_TRANSPORT_ERROR: + case ChannelError::TRANSPORT_ERROR: return proto::CHANNEL_ERROR_TRANSPORT_ERROR; - case CHANNEL_ERROR_INVALID_MESSAGE: + case ChannelError::INVALID_MESSAGE: return proto::CHANNEL_ERROR_INVALID_MESSAGE; - case CHANNEL_ERROR_INVALID_CHANNEL_ID: + case ChannelError::INVALID_CHANNEL_ID: return proto::CHANNEL_ERROR_INVALID_CHANNEL_ID; - case CHANNEL_ERROR_CONNECT_TIMEOUT: + case ChannelError::CONNECT_TIMEOUT: return proto::CHANNEL_ERROR_CONNECT_TIMEOUT; - case CHANNEL_ERROR_UNKNOWN: + case ChannelError::UNKNOWN: return proto::CHANNEL_ERROR_UNKNOWN; default: NOTREACHED(); @@ -209,7 +210,8 @@ } void CastTransportImpl::SetErrorState(ChannelError error_state) { - VLOG_WITH_CONNECTION(2) << "SetErrorState: " << error_state; + VLOG_WITH_CONNECTION(2) << "SetErrorState: " + << ::cast_channel::ChannelErrorToString(error_state); error_state_ = error_state; } @@ -250,7 +252,7 @@ default: NOTREACHED() << "Unknown state in write state machine: " << state; SetWriteState(WRITE_STATE_ERROR); - SetErrorState(CHANNEL_ERROR_UNKNOWN); + SetErrorState(ChannelError::UNKNOWN); rv = net::ERR_FAILED; break; } @@ -258,7 +260,7 @@ if (write_state_ == WRITE_STATE_ERROR) { FlushWriteQueue(); - DCHECK_NE(CHANNEL_ERROR_NONE, error_state_); + DCHECK_NE(ChannelError::NONE, error_state_); VLOG_WITH_CONNECTION(2) << "Sending OnError()."; delegate_->OnError(error_state_); } @@ -285,7 +287,7 @@ DCHECK(!write_queue_.empty()); if (result <= 0) { // NOTE that 0 also indicates an error logger_->LogSocketEventWithRv(channel_id_, proto::SOCKET_WRITE, result); - SetErrorState(CHANNEL_ERROR_SOCKET_ERROR); + SetErrorState(ChannelError::CAST_SOCKET_ERROR); SetWriteState(WRITE_STATE_HANDLE_ERROR); return result == 0 ? net::ERR_FAILED : result; } @@ -323,7 +325,7 @@ int CastTransportImpl::DoWriteHandleError(int result) { VLOG_WITH_CONNECTION(2) << "DoWriteHandleError result=" << result; - DCHECK_NE(CHANNEL_ERROR_NONE, error_state_); + DCHECK_NE(ChannelError::NONE, error_state_); DCHECK_LT(result, 0); SetWriteState(WRITE_STATE_ERROR); return net::ERR_FAILED; @@ -372,7 +374,7 @@ default: NOTREACHED() << "Unknown state in read state machine: " << state; SetReadState(READ_STATE_ERROR); - SetErrorState(CHANNEL_ERROR_UNKNOWN); + SetErrorState(ChannelError::UNKNOWN); rv = net::ERR_FAILED; break; } @@ -404,7 +406,7 @@ if (result <= 0) { logger_->LogSocketEventWithRv(channel_id_, proto::SOCKET_READ, result); VLOG_WITH_CONNECTION(1) << "Read error, peer closed the socket."; - SetErrorState(CHANNEL_ERROR_SOCKET_ERROR); + SetErrorState(ChannelError::CAST_SOCKET_ERROR); SetReadState(READ_STATE_HANDLE_ERROR); return result == 0 ? net::ERR_FAILED : result; } @@ -413,12 +415,12 @@ DCHECK(!current_message_); ChannelError framing_error; current_message_ = framer_->Ingest(result, &message_size, &framing_error); - if (current_message_.get() && (framing_error == CHANNEL_ERROR_NONE)) { + if (current_message_.get() && (framing_error == ChannelError::NONE)) { DCHECK_GT(message_size, static_cast<size_t>(0)); SetReadState(READ_STATE_DO_CALLBACK); - } else if (framing_error != CHANNEL_ERROR_NONE) { + } else if (framing_error != ChannelError::NONE) { DCHECK(!current_message_); - SetErrorState(CHANNEL_ERROR_INVALID_MESSAGE); + SetErrorState(ChannelError::INVALID_MESSAGE); SetReadState(READ_STATE_HANDLE_ERROR); } else { DCHECK(!current_message_); @@ -431,7 +433,7 @@ VLOG_WITH_CONNECTION(2) << "DoReadCallback"; if (!IsCastMessageValid(*current_message_)) { SetReadState(READ_STATE_HANDLE_ERROR); - SetErrorState(CHANNEL_ERROR_INVALID_MESSAGE); + SetErrorState(ChannelError::INVALID_MESSAGE); return net::ERR_INVALID_RESPONSE; } SetReadState(READ_STATE_READ); @@ -442,7 +444,7 @@ int CastTransportImpl::DoReadHandleError(int result) { VLOG_WITH_CONNECTION(2) << "DoReadHandleError"; - DCHECK_NE(CHANNEL_ERROR_NONE, error_state_); + DCHECK_NE(ChannelError::NONE, error_state_); DCHECK_LE(result, 0); SetReadState(READ_STATE_ERROR); return net::ERR_FAILED;
diff --git a/extensions/browser/api/cast_channel/cast_transport.h b/extensions/browser/api/cast_channel/cast_transport.h index ba67ee8f..68769e1 100644 --- a/extensions/browser/api/cast_channel/cast_transport.h +++ b/extensions/browser/api/cast_channel/cast_transport.h
@@ -12,8 +12,8 @@ #include "base/memory/ref_counted.h" #include "base/sequence_checker.h" #include "base/threading/thread_checker.h" +#include "components/cast_channel/cast_channel_enum.h" #include "extensions/browser/api/cast_channel/logger.h" -#include "extensions/common/api/cast_channel.h" #include "extensions/common/api/cast_channel/logging.pb.h" #include "net/base/completion_callback.h" #include "net/base/ip_endpoint.h" @@ -38,6 +38,8 @@ // Object to be informed of incoming messages and read errors. class Delegate { public: + using ChannelError = ::cast_channel::ChannelError; + virtual ~Delegate() {} // Called once Transport is successfully initialized and started. @@ -74,6 +76,9 @@ // Manager class for reading and writing messages to/from a socket. class CastTransportImpl : public CastTransport { public: + using ChannelAuthType = ::cast_channel::ChannelAuthType; + using ChannelError = ::cast_channel::ChannelError; + // Adds a CastMessage read/write layer to a socket. // Message read events are propagated to the owner via |read_delegate|. // |vlog_prefix| sets the prefix used for all VLOGged output.
diff --git a/extensions/browser/api/cast_channel/cast_transport_unittest.cc b/extensions/browser/api/cast_channel/cast_transport_unittest.cc index aad1a9c1..90374d4 100644 --- a/extensions/browser/api/cast_channel/cast_transport_unittest.cc +++ b/extensions/browser/api/cast_channel/cast_transport_unittest.cc
@@ -146,6 +146,9 @@ class CastTransportTest : public testing::Test { public: + using ChannelError = ::cast_channel::ChannelError; + using ChannelAuthType = ::cast_channel::ChannelAuthType; + CastTransportTest() : logger_(new Logger()) { delegate_ = new MockCastTransportDelegate; transport_.reset(new CastTransportImpl(&mock_socket_, kChannelId, @@ -241,7 +244,7 @@ EXPECT_CALL(mock_socket_, Write(NotNull(), _, _)).WillOnce( DoAll(EnqueueCallback<2>(&socket_cbs), Return(net::ERR_IO_PENDING))); EXPECT_CALL(write_handler, Complete(net::ERR_FAILED)); - EXPECT_CALL(*delegate_, OnError(CHANNEL_ERROR_SOCKET_ERROR)); + EXPECT_CALL(*delegate_, OnError(ChannelError::CAST_SOCKET_ERROR)); transport_->SendMessage( message, base::Bind(&CompleteHandler::Complete, base::Unretained(&write_handler))); @@ -422,7 +425,7 @@ Return(net::ERR_IO_PENDING))) .RetiresOnSaturation(); - EXPECT_CALL(*delegate_, OnError(CHANNEL_ERROR_SOCKET_ERROR)); + EXPECT_CALL(*delegate_, OnError(ChannelError::CAST_SOCKET_ERROR)); transport_->Start(); // Header read failure. socket_cbs.Pop(net::ERR_CONNECTION_RESET); @@ -460,7 +463,7 @@ EnqueueCallback<2>(&socket_cbs), Return(net::ERR_IO_PENDING))) .RetiresOnSaturation(); - EXPECT_CALL(*delegate_, OnError(CHANNEL_ERROR_SOCKET_ERROR)); + EXPECT_CALL(*delegate_, OnError(ChannelError::CAST_SOCKET_ERROR)); transport_->Start(); // Header read is OK. socket_cbs.Pop(MessageFramer::MessageHeader::header_size()); @@ -507,7 +510,7 @@ Return(net::ERR_IO_PENDING))) .RetiresOnSaturation(); - EXPECT_CALL(*delegate_, OnError(CHANNEL_ERROR_INVALID_MESSAGE)); + EXPECT_CALL(*delegate_, OnError(ChannelError::INVALID_MESSAGE)); transport_->Start(); socket_cbs.Pop(MessageFramer::MessageHeader::header_size()); socket_cbs.Pop(serialized_message.size() - @@ -606,7 +609,7 @@ .WillOnce(DoAll(FillBufferFromString<0>(serialized_message), Return(net::ERR_CONNECTION_RESET))) .RetiresOnSaturation(); - EXPECT_CALL(*delegate_, OnError(CHANNEL_ERROR_SOCKET_ERROR)); + EXPECT_CALL(*delegate_, OnError(ChannelError::CAST_SOCKET_ERROR)); transport_->Start(); } @@ -635,7 +638,7 @@ MessageFramer::MessageHeader::header_size() - 1)), Return(net::ERR_CONNECTION_RESET))) .RetiresOnSaturation(); - EXPECT_CALL(*delegate_, OnError(CHANNEL_ERROR_SOCKET_ERROR)); + EXPECT_CALL(*delegate_, OnError(ChannelError::CAST_SOCKET_ERROR)); transport_->Start(); EXPECT_EQ(proto::SOCKET_READ, logger_->GetLastErrors(kChannelId).event_type); EXPECT_EQ(net::ERR_CONNECTION_RESET, @@ -676,7 +679,7 @@ Return(serialized_message.size() - MessageFramer::MessageHeader::header_size()))) .RetiresOnSaturation(); - EXPECT_CALL(*delegate_, OnError(CHANNEL_ERROR_INVALID_MESSAGE)); + EXPECT_CALL(*delegate_, OnError(ChannelError::INVALID_MESSAGE)); transport_->Start(); } } // namespace cast_channel
diff --git a/extensions/browser/api/cast_channel/keep_alive_delegate.cc b/extensions/browser/api/cast_channel/keep_alive_delegate.cc index 71adb89b..c6803eb 100644 --- a/extensions/browser/api/cast_channel/keep_alive_delegate.cc +++ b/extensions/browser/api/cast_channel/keep_alive_delegate.cc
@@ -48,6 +48,8 @@ // static const char KeepAliveDelegate::kHeartbeatPongType[] = "PONG"; +using ::cast_channel::ChannelError; + // static CastMessage KeepAliveDelegate::CreateKeepAliveMessage( const char* message_type) { @@ -146,19 +148,20 @@ // An error occurred while sending the ping response. VLOG(1) << "Error sending " << message_type; logger_->LogSocketEventWithRv(socket_->id(), proto::PING_WRITE_ERROR, rv); - OnError(cast_channel::CHANNEL_ERROR_SOCKET_ERROR); + OnError(ChannelError::CAST_SOCKET_ERROR); } } void KeepAliveDelegate::LivenessTimeout() { - OnError(cast_channel::CHANNEL_ERROR_PING_TIMEOUT); + OnError(ChannelError::PING_TIMEOUT); Stop(); } // CastTransport::Delegate interface. void KeepAliveDelegate::OnError(ChannelError error_state) { DCHECK(thread_checker_.CalledOnValidThread()); - VLOG(1) << "KeepAlive::OnError: " << error_state; + VLOG(1) << "KeepAlive::OnError: " + << ::cast_channel::ChannelErrorToString(error_state); inner_delegate_->OnError(error_state); Stop(); }
diff --git a/extensions/browser/api/cast_channel/keep_alive_delegate_unittest.cc b/extensions/browser/api/cast_channel/keep_alive_delegate_unittest.cc index d9e946b..cc46dd5d 100644 --- a/extensions/browser/api/cast_channel/keep_alive_delegate_unittest.cc +++ b/extensions/browser/api/cast_channel/keep_alive_delegate_unittest.cc
@@ -49,6 +49,8 @@ class KeepAliveDelegateTest : public testing::Test { public: + using ChannelError = ::cast_channel::ChannelError; + KeepAliveDelegateTest() {} ~KeepAliveDelegateTest() override {} @@ -87,7 +89,7 @@ }; TEST_F(KeepAliveDelegateTest, TestErrorHandledBeforeStarting) { - keep_alive_->OnError(CHANNEL_ERROR_CONNECT_ERROR); + keep_alive_->OnError(ChannelError::CONNECT_ERROR); } TEST_F(KeepAliveDelegateTest, TestPing) { @@ -115,7 +117,7 @@ _)) .WillOnce(PostCompletionCallbackTask<1>(net::ERR_CONNECTION_RESET)); EXPECT_CALL(*inner_delegate_, Start()); - EXPECT_CALL(*inner_delegate_, OnError(CHANNEL_ERROR_SOCKET_ERROR)); + EXPECT_CALL(*inner_delegate_, OnError(ChannelError::CAST_SOCKET_ERROR)); EXPECT_CALL(*ping_timer_, ResetTriggered()).Times(1); EXPECT_CALL(*liveness_timer_, ResetTriggered()).Times(1); EXPECT_CALL(*liveness_timer_, Stop()); @@ -136,7 +138,7 @@ KeepAliveDelegate::kHeartbeatPingType)), _)) .WillOnce(PostCompletionCallbackTask<1>(net::OK)); - EXPECT_CALL(*inner_delegate_, OnError(CHANNEL_ERROR_PING_TIMEOUT)); + EXPECT_CALL(*inner_delegate_, OnError(ChannelError::PING_TIMEOUT)); EXPECT_CALL(*inner_delegate_, Start()); EXPECT_CALL(*ping_timer_, ResetTriggered()).Times(1); EXPECT_CALL(*liveness_timer_, ResetTriggered()).Times(1); @@ -182,7 +184,7 @@ .Times(1) .InSequence(message_and_error_sequence) .RetiresOnSaturation(); - EXPECT_CALL(*inner_delegate_, OnError(CHANNEL_ERROR_INVALID_MESSAGE)) + EXPECT_CALL(*inner_delegate_, OnError(ChannelError::INVALID_MESSAGE)) .Times(1) .InSequence(message_and_error_sequence); EXPECT_CALL(*inner_delegate_, OnMessage(EqualsProto(message_after_error))) @@ -199,7 +201,7 @@ keep_alive_->Start(); keep_alive_->OnMessage(message); RunPendingTasks(); - keep_alive_->OnError(CHANNEL_ERROR_INVALID_MESSAGE); + keep_alive_->OnError(ChannelError::INVALID_MESSAGE); RunPendingTasks(); // Process a non-PING/PONG message and expect it to pass through.
diff --git a/gpu/config/gpu_driver_bug_list.json b/gpu/config/gpu_driver_bug_list.json index 15aa3aa3..77629e4 100644 --- a/gpu/config/gpu_driver_bug_list.json +++ b/gpu/config/gpu_driver_bug_list.json
@@ -2401,13 +2401,13 @@ }, { "id": 224, - "description": "VPx decoding isn't supported before Windows 10 anniversary update.", - "cr_bugs": [616318], + "description": "VPx decoding isn't supported well before Windows 10 creators update.", + "cr_bugs": [616318, 667532], "os": { "type": "win", "version": { "op": "<", - "value": "10.0.14393" + "value": "10.0.15063" } }, "features": [
diff --git a/ios/chrome/browser/ui/autofill/autofill_ui_type.h b/ios/chrome/browser/ui/autofill/autofill_ui_type.h index 9a408bb..72768b28 100644 --- a/ios/chrome/browser/ui/autofill/autofill_ui_type.h +++ b/ios/chrome/browser/ui/autofill/autofill_ui_type.h
@@ -15,6 +15,7 @@ AutofillUITypeCreditCardExpMonth, AutofillUITypeCreditCardExpYear, AutofillUITypeCreditCardBillingAddress, + AutofillUITypeCreditCardSaveToChrome, AutofillUITypeProfileFullName, AutofillUITypeProfileCompanyName, AutofillUITypeProfileHomeAddressStreet,
diff --git a/ios/chrome/browser/ui/payments/BUILD.gn b/ios/chrome/browser/ui/payments/BUILD.gn index c5dac5aa..f37688f 100644 --- a/ios/chrome/browser/ui/payments/BUILD.gn +++ b/ios/chrome/browser/ui/payments/BUILD.gn
@@ -11,8 +11,6 @@ "address_edit_coordinator.mm", "address_edit_mediator.h", "address_edit_mediator.mm", - "address_edit_view_controller.h", - "address_edit_view_controller.mm", "country_selection_coordinator.h", "country_selection_coordinator.mm", "credit_card_edit_coordinator.h", @@ -91,15 +89,11 @@ source_set("payments_ui") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ - "credit_card_edit_view_controller.h", - "credit_card_edit_view_controller.mm", - "credit_card_edit_view_controller_data_source.h", "payment_items_display_view_controller.h", "payment_items_display_view_controller.mm", "payment_items_display_view_controller_actions.h", "payment_items_display_view_controller_data_source.h", "payment_request_edit_consumer.h", - "payment_request_edit_view_controller+internal.h", "payment_request_edit_view_controller.h", "payment_request_edit_view_controller.mm", "payment_request_edit_view_controller_actions.h", @@ -143,7 +137,6 @@ "address_edit_coordinator_unittest.mm", "country_selection_coordinator_unittest.mm", "credit_card_edit_coordinator_unittest.mm", - "credit_card_edit_view_controller_unittest.mm", "payment_items_display_coordinator_unittest.mm", "payment_items_display_view_controller_unittest.mm", "payment_method_selection_coordinator_unittest.mm",
diff --git a/ios/chrome/browser/ui/payments/address_edit_coordinator.h b/ios/chrome/browser/ui/payments/address_edit_coordinator.h index 799fb224..f6f8a3b6 100644 --- a/ios/chrome/browser/ui/payments/address_edit_coordinator.h +++ b/ios/chrome/browser/ui/payments/address_edit_coordinator.h
@@ -6,7 +6,6 @@ #define IOS_CHROME_BROWSER_UI_PAYMENTS_ADDRESS_EDIT_COORDINATOR_H_ #import "ios/chrome/browser/chrome_coordinator.h" -#import "ios/chrome/browser/ui/payments/address_edit_view_controller.h" #import "ios/chrome/browser/ui/payments/country_selection_coordinator.h" #import "ios/chrome/browser/ui/payments/payment_request_edit_view_controller.h" @@ -38,7 +37,7 @@ // controller. This view controller will be presented by the view controller // provided in the initializer. @interface AddressEditCoordinator - : ChromeCoordinator<AddressEditViewControllerDelegate, + : ChromeCoordinator<PaymentRequestEditViewControllerDelegate, PaymentRequestEditViewControllerValidator, CountrySelectionCoordinatorDelegate>
diff --git a/ios/chrome/browser/ui/payments/address_edit_coordinator.mm b/ios/chrome/browser/ui/payments/address_edit_coordinator.mm index 4d4c78e1..8e06e94 100644 --- a/ios/chrome/browser/ui/payments/address_edit_coordinator.mm +++ b/ios/chrome/browser/ui/payments/address_edit_coordinator.mm
@@ -31,7 +31,7 @@ @property(nonatomic, strong) CountrySelectionCoordinator* countrySelectionCoordinator; -@property(nonatomic, strong) AddressEditViewController* viewController; +@property(nonatomic, strong) PaymentRequestEditViewController* viewController; @property(nonatomic, strong) AddressEditMediator* mediator; @@ -47,7 +47,7 @@ @synthesize mediator = _mediator; - (void)start { - self.viewController = [[AddressEditViewController alloc] init]; + self.viewController = [[PaymentRequestEditViewController alloc] init]; // TODO(crbug.com/602666): Title varies depending on what field is missing. // e.g., Add Email vs. Add Phone Number. NSString* title = self.address @@ -88,7 +88,7 @@ return nil; } -#pragma mark - AddressEditViewControllerDelegate +#pragma mark - PaymentRequestEditViewControllerDelegate - (void)paymentRequestEditViewController: (PaymentRequestEditViewController*)controller @@ -104,8 +104,9 @@ } } -- (void)addressEditViewController:(AddressEditViewController*)controller - didFinishEditingFields:(NSArray<EditorField*>*)fields { +- (void)paymentRequestEditViewController: + (PaymentRequestEditViewController*)controller + didFinishEditingFields:(NSArray<EditorField*>*)fields { // Create an empty autofill profile. If an address is being edited, copy over // the information. autofill::AutofillProfile address = @@ -136,8 +137,8 @@ didFinishEditingAddress:self.address]; } -- (void)addressEditViewControllerDidCancel: - (AddressEditViewController*)controller { +- (void)paymentRequestEditViewControllerDidCancel: + (PaymentRequestEditViewController*)controller { [self.delegate addressEditCoordinatorDidCancel:self]; }
diff --git a/ios/chrome/browser/ui/payments/address_edit_coordinator_unittest.mm b/ios/chrome/browser/ui/payments/address_edit_coordinator_unittest.mm index bad6de67..30fa649 100644 --- a/ios/chrome/browser/ui/payments/address_edit_coordinator_unittest.mm +++ b/ios/chrome/browser/ui/payments/address_edit_coordinator_unittest.mm
@@ -16,7 +16,7 @@ #include "components/prefs/pref_service.h" #include "ios/chrome/browser/payments/payment_request_test_util.h" #include "ios/chrome/browser/payments/test_payment_request.h" -#import "ios/chrome/browser/ui/payments/address_edit_view_controller.h" +#import "ios/chrome/browser/ui/payments/payment_request_edit_view_controller.h" #import "ios/chrome/browser/ui/payments/payment_request_editor_field.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -178,11 +178,11 @@ EXPECT_CALL(personal_data_manager_, UpdateProfile(_)).Times(0); // Call the controller delegate method. - AddressEditViewController* view_controller = - base::mac::ObjCCastStrict<AddressEditViewController>( + PaymentRequestEditViewController* view_controller = + base::mac::ObjCCastStrict<PaymentRequestEditViewController>( navigation_controller.visibleViewController); - [coordinator addressEditViewController:view_controller - didFinishEditingFields:GetEditorFields()]; + [coordinator paymentRequestEditViewController:view_controller + didFinishEditingFields:GetEditorFields()]; EXPECT_OCMOCK_VERIFY(delegate); } @@ -233,11 +233,11 @@ .Times(1); // Call the controller delegate method. - AddressEditViewController* view_controller = - base::mac::ObjCCastStrict<AddressEditViewController>( + PaymentRequestEditViewController* view_controller = + base::mac::ObjCCastStrict<PaymentRequestEditViewController>( navigation_controller.visibleViewController); - [coordinator addressEditViewController:view_controller - didFinishEditingFields:GetEditorFields()]; + [coordinator paymentRequestEditViewController:view_controller + didFinishEditingFields:GetEditorFields()]; EXPECT_OCMOCK_VERIFY(delegate); } @@ -269,10 +269,10 @@ EXPECT_EQ(2u, navigation_controller.viewControllers.count); // Call the controller delegate method. - AddressEditViewController* view_controller = - base::mac::ObjCCastStrict<AddressEditViewController>( + PaymentRequestEditViewController* view_controller = + base::mac::ObjCCastStrict<PaymentRequestEditViewController>( navigation_controller.visibleViewController); - [coordinator addressEditViewControllerDidCancel:view_controller]; + [coordinator paymentRequestEditViewControllerDidCancel:view_controller]; EXPECT_OCMOCK_VERIFY(delegate); }
diff --git a/ios/chrome/browser/ui/payments/address_edit_mediator.mm b/ios/chrome/browser/ui/payments/address_edit_mediator.mm index 3f872b2..9b7b3fc 100644 --- a/ios/chrome/browser/ui/payments/address_edit_mediator.mm +++ b/ios/chrome/browser/ui/payments/address_edit_mediator.mm
@@ -118,6 +118,10 @@ return NO; } +- (UIImage*)iconIdentifyingEditorField:(EditorField*)field { + return nil; +} + #pragma mark - RegionDataLoaderConsumer - (void)regionDataLoaderDidSucceedWithRegions:
diff --git a/ios/chrome/browser/ui/payments/address_edit_view_controller.h b/ios/chrome/browser/ui/payments/address_edit_view_controller.h deleted file mode 100644 index be84f49..0000000 --- a/ios/chrome/browser/ui/payments/address_edit_view_controller.h +++ /dev/null
@@ -1,39 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_PAYMENTS_ADDRESS_EDIT_VIEW_CONTROLLER_H_ -#define IOS_CHROME_BROWSER_UI_PAYMENTS_ADDRESS_EDIT_VIEW_CONTROLLER_H_ - -#import "ios/chrome/browser/ui/payments/payment_request_edit_view_controller.h" - -@class AddressEditViewController; -@class EditorField; - -// Delegate protocol for AddressEditViewController. -@protocol - AddressEditViewControllerDelegate<PaymentRequestEditViewControllerDelegate> - -// Notifies the delegate that the user has finished editing the address editor -// fields. -- (void)addressEditViewController:(AddressEditViewController*)controller - didFinishEditingFields:(NSArray<EditorField*>*)fields; - -// Notifies the delegate that the user has chosen to discard entries in the -// address editor fields and return to the previous screen. -- (void)addressEditViewControllerDidCancel: - (AddressEditViewController*)controller; - -@end - -// View controller responsible for presenting an address edit form. The form -// features text fields for the field definitions passed to the initializer. -@interface AddressEditViewController : PaymentRequestEditViewController - -// The delegate to be notified when the user returns or finishes editing the -// address editor fields. -@property(nonatomic, weak) id<AddressEditViewControllerDelegate> delegate; - -@end - -#endif // IOS_CHROME_BROWSER_UI_PAYMENTS_ADDRESS_EDIT_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/payments/address_edit_view_controller.mm b/ios/chrome/browser/ui/payments/address_edit_view_controller.mm deleted file mode 100644 index d06eb3b..0000000 --- a/ios/chrome/browser/ui/payments/address_edit_view_controller.mm +++ /dev/null
@@ -1,69 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/ui/payments/address_edit_view_controller.h" - -#include "components/strings/grit/components_strings.h" -#import "ios/chrome/browser/ui/payments/payment_request_edit_view_controller+internal.h" -#import "ios/chrome/browser/ui/payments/payment_request_editor_field.h" -#include "ui/base/l10n/l10n_util.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -namespace { - -NSString* const kAddressEditCollectionViewAccessibilityID = - @"kAddressEditCollectionViewAccessibilityID"; - -} // namespace - -@interface AddressEditViewController () - -// The list of field definitions for the editor. -@property(nonatomic, weak) NSArray<EditorField*>* fields; - -@end - -@implementation AddressEditViewController - -@synthesize delegate = _delegate; -@synthesize fields = _fields; - -#pragma mark - Setters - -- (void)setDelegate:(id<AddressEditViewControllerDelegate>)delegate { - [super setDelegate:delegate]; - _delegate = delegate; -} - -#pragma mark - CollectionViewController methods - -- (void)viewDidLoad { - [super viewDidLoad]; - - self.collectionView.accessibilityIdentifier = - kAddressEditCollectionViewAccessibilityID; -} - -#pragma mark - PaymentRequestEditViewControllerActions methods - -- (void)onCancel { - [super onCancel]; - - [self.delegate addressEditViewControllerDidCancel:self]; -} - -- (void)onDone { - [super onDone]; - - if (![self validateForm]) - return; - - [self.delegate addressEditViewController:self - didFinishEditingFields:self.fields]; -} - -@end
diff --git a/ios/chrome/browser/ui/payments/credit_card_edit_coordinator.h b/ios/chrome/browser/ui/payments/credit_card_edit_coordinator.h index da3037df..0a4fdd57 100644 --- a/ios/chrome/browser/ui/payments/credit_card_edit_coordinator.h +++ b/ios/chrome/browser/ui/payments/credit_card_edit_coordinator.h
@@ -6,7 +6,6 @@ #define IOS_CHROME_BROWSER_UI_PAYMENTS_CREDIT_CARD_EDIT_COORDINATOR_H_ #import "ios/chrome/browser/chrome_coordinator.h" -#import "ios/chrome/browser/ui/payments/credit_card_edit_view_controller.h" #import "ios/chrome/browser/ui/payments/payment_request_edit_view_controller.h" namespace autofill { @@ -38,7 +37,7 @@ // controller. This view controller will be presented by the view controller // provided in the initializer. @interface CreditCardEditCoordinator - : ChromeCoordinator<CreditCardEditViewControllerDelegate, + : ChromeCoordinator<PaymentRequestEditViewControllerDelegate, PaymentRequestEditViewControllerValidator> // The credit card to be edited, if any. This pointer is not owned by this class
diff --git a/ios/chrome/browser/ui/payments/credit_card_edit_coordinator.mm b/ios/chrome/browser/ui/payments/credit_card_edit_coordinator.mm index 693cc92..68f03b68 100644 --- a/ios/chrome/browser/ui/payments/credit_card_edit_coordinator.mm +++ b/ios/chrome/browser/ui/payments/credit_card_edit_coordinator.mm
@@ -65,7 +65,7 @@ } // namespace @interface CreditCardEditCoordinator () { - CreditCardEditViewController* _viewController; + PaymentRequestEditViewController* _viewController; CreditCardEditViewControllerMediator* _mediator; } @@ -79,7 +79,7 @@ @synthesize delegate = _delegate; - (void)start { - _viewController = [[CreditCardEditViewController alloc] init]; + _viewController = [[PaymentRequestEditViewController alloc] init]; // TODO(crbug.com/602666): Title varies depending on the missing fields. NSString* title = _creditCard ? l10n_util::GetNSString(IDS_PAYMENTS_EDIT_CARD) @@ -132,7 +132,7 @@ return nil; } -#pragma mark - CreditCardEditViewControllerDelegate +#pragma mark - PaymentRequestEditViewControllerDelegate - (void)paymentRequestEditViewController: (PaymentRequestEditViewController*)controller @@ -142,9 +142,10 @@ } } -- (void)creditCardEditViewController:(CreditCardEditViewController*)controller - didFinishEditingFields:(NSArray<EditorField*>*)fields - saveCreditCard:(BOOL)saveCreditCard { +- (void)paymentRequestEditViewController: + (PaymentRequestEditViewController*)controller + didFinishEditingFields:(NSArray<EditorField*>*)fields { + BOOL saveCreditCard = NO; // Create an empty credit card. If a credit card is being edited, copy over // the information. autofill::CreditCard creditCard = @@ -153,7 +154,9 @@ autofill::kSettingsOrigin); for (EditorField* field in fields) { - if (field.autofillUIType == AutofillUITypeCreditCardBillingAddress) { + if (field.autofillUIType == AutofillUITypeCreditCardSaveToChrome) { + saveCreditCard = [field.value boolValue]; + } else if (field.autofillUIType == AutofillUITypeCreditCardBillingAddress) { creditCard.set_billing_address_id(base::SysNSStringToUTF8(field.value)); } else { creditCard.SetRawInfo( @@ -188,8 +191,8 @@ didFinishEditingCreditCard:_creditCard]; } -- (void)creditCardEditViewControllerDidCancel: - (CreditCardEditViewController*)controller { +- (void)paymentRequestEditViewControllerDidCancel: + (PaymentRequestEditViewController*)controller { [_delegate creditCardEditCoordinatorDidCancel:self]; }
diff --git a/ios/chrome/browser/ui/payments/credit_card_edit_coordinator_unittest.mm b/ios/chrome/browser/ui/payments/credit_card_edit_coordinator_unittest.mm index 8a7eaa1..ff8e42f 100644 --- a/ios/chrome/browser/ui/payments/credit_card_edit_coordinator_unittest.mm +++ b/ios/chrome/browser/ui/payments/credit_card_edit_coordinator_unittest.mm
@@ -14,7 +14,6 @@ #include "ios/chrome/browser/payments/payment_request.h" #include "ios/chrome/browser/payments/payment_request_test_util.h" #import "ios/chrome/browser/ui/autofill/autofill_ui_type.h" -#import "ios/chrome/browser/ui/payments/credit_card_edit_view_controller.h" #import "ios/chrome/browser/ui/payments/payment_request_editor_field.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -61,7 +60,7 @@ arg.billing_address_id() == billing_address_id; } -NSArray<EditorField*>* GetEditorFields() { +NSArray<EditorField*>* GetEditorFields(bool save_card) { return @[ [[EditorField alloc] initWithAutofillUIType:AutofillUITypeCreditCardNumber fieldType:EditorFieldTypeTextField @@ -90,6 +89,12 @@ label:@"Billing Address" value:@"12345" required:YES], + [[EditorField alloc] + initWithAutofillUIType:AutofillUITypeCreditCardSaveToChrome + fieldType:EditorFieldTypeSwitch + label:@"Save Card" + value:save_card ? @"YES" : @"NO" + required:YES], ]; } @@ -178,12 +183,11 @@ EXPECT_CALL(personal_data_manager_, UpdateCreditCard(_)).Times(0); // Call the controller delegate method. - CreditCardEditViewController* view_controller = - base::mac::ObjCCastStrict<CreditCardEditViewController>( + PaymentRequestEditViewController* view_controller = + base::mac::ObjCCastStrict<PaymentRequestEditViewController>( navigation_controller.visibleViewController); - [coordinator creditCardEditViewController:view_controller - didFinishEditingFields:GetEditorFields() - saveCreditCard:YES]; + [coordinator paymentRequestEditViewController:view_controller + didFinishEditingFields:GetEditorFields(true)]; EXPECT_OCMOCK_VERIFY(delegate); } @@ -230,12 +234,11 @@ EXPECT_CALL(personal_data_manager_, UpdateCreditCard(_)).Times(0); // Call the controller delegate method. - CreditCardEditViewController* view_controller = - base::mac::ObjCCastStrict<CreditCardEditViewController>( + PaymentRequestEditViewController* view_controller = + base::mac::ObjCCastStrict<PaymentRequestEditViewController>( navigation_controller.visibleViewController); - [coordinator creditCardEditViewController:view_controller - didFinishEditingFields:GetEditorFields() - saveCreditCard:NO]; + [coordinator paymentRequestEditViewController:view_controller + didFinishEditingFields:GetEditorFields(false)]; EXPECT_OCMOCK_VERIFY(delegate); } @@ -285,12 +288,11 @@ .Times(1); // Call the controller delegate method. - CreditCardEditViewController* view_controller = - base::mac::ObjCCastStrict<CreditCardEditViewController>( + PaymentRequestEditViewController* view_controller = + base::mac::ObjCCastStrict<PaymentRequestEditViewController>( navigation_controller.visibleViewController); - [coordinator creditCardEditViewController:view_controller - didFinishEditingFields:GetEditorFields() - saveCreditCard:YES]; + [coordinator paymentRequestEditViewController:view_controller + didFinishEditingFields:GetEditorFields(true)]; EXPECT_OCMOCK_VERIFY(delegate); } @@ -322,10 +324,10 @@ EXPECT_EQ(2u, navigation_controller.viewControllers.count); // Call the controller delegate method. - CreditCardEditViewController* view_controller = - base::mac::ObjCCastStrict<CreditCardEditViewController>( + PaymentRequestEditViewController* view_controller = + base::mac::ObjCCastStrict<PaymentRequestEditViewController>( navigation_controller.visibleViewController); - [coordinator creditCardEditViewControllerDidCancel:view_controller]; + [coordinator paymentRequestEditViewControllerDidCancel:view_controller]; EXPECT_OCMOCK_VERIFY(delegate); }
diff --git a/ios/chrome/browser/ui/payments/credit_card_edit_mediator.h b/ios/chrome/browser/ui/payments/credit_card_edit_mediator.h index 9a19d4f..c020d121 100644 --- a/ios/chrome/browser/ui/payments/credit_card_edit_mediator.h +++ b/ios/chrome/browser/ui/payments/credit_card_edit_mediator.h
@@ -5,7 +5,7 @@ #ifndef IOS_CHROME_BROWSER_UI_PAYMENTS_CREDIT_CARD_EDIT_MEDIATOR_H_ #define IOS_CHROME_BROWSER_UI_PAYMENTS_CREDIT_CARD_EDIT_MEDIATOR_H_ -#import "ios/chrome/browser/ui/payments/credit_card_edit_view_controller_data_source.h" +#import "ios/chrome/browser/ui/payments/payment_request_edit_view_controller_data_source.h" class PaymentRequest; @protocol PaymentRequestEditConsumer; @@ -16,7 +16,7 @@ // Serves as data source for CreditCardEditViewController. @interface CreditCardEditViewControllerMediator - : NSObject<CreditCardEditViewControllerDataSource> + : NSObject<PaymentRequestEditViewControllerDataSource> // The consumer for this object. This can change during the lifetime of this // object and may be nil.
diff --git a/ios/chrome/browser/ui/payments/credit_card_edit_mediator.mm b/ios/chrome/browser/ui/payments/credit_card_edit_mediator.mm index 13e75e4..2b71da3 100644 --- a/ios/chrome/browser/ui/payments/credit_card_edit_mediator.mm +++ b/ios/chrome/browser/ui/payments/credit_card_edit_mediator.mm
@@ -15,7 +15,6 @@ #include "ios/chrome/browser/payments/payment_request.h" #import "ios/chrome/browser/payments/payment_request_util.h" #import "ios/chrome/browser/ui/autofill/autofill_ui_type.h" -#import "ios/chrome/browser/ui/autofill/autofill_ui_type_util.h" #import "ios/chrome/browser/ui/payments/cells/accepted_payment_methods_item.h" #import "ios/chrome/browser/ui/payments/cells/payment_method_item.h" #import "ios/chrome/browser/ui/payments/payment_request_edit_consumer.h" @@ -28,7 +27,6 @@ #endif namespace { -using ::AutofillUITypeFromAutofillType; using ::autofill::data_util::GetIssuerNetworkForBasicCardIssuerNetwork; using ::autofill::data_util::GetPaymentRequestData; using ::payment_request_util::GetBillingAddressLabelFromAutofillProfile; @@ -73,7 +71,7 @@ [self.consumer setEditorFields:[self createEditorFields]]; } -#pragma mark - CreditCardEditViewControllerDataSource +#pragma mark - PaymentRequestEditViewControllerDataSource - (CollectionViewItem*)headerItem { if (_creditCard && !autofill::IsCreditCardLocal(*_creditCard)) { @@ -118,9 +116,13 @@ return !_creditCard || autofill::IsCreditCardLocal(*_creditCard); } -- (UIImage*)cardTypeIconFromCardNumber:(NSString*)cardNumber { +- (UIImage*)iconIdentifyingEditorField:(EditorField*)field { + // Early return if the field is not the credit card number field. + if (field.autofillUIType != AutofillUITypeCreditCardNumber) + return nil; + const char* issuerNetwork = autofill::CreditCard::GetCardNetwork( - base::SysNSStringToUTF16(cardNumber)); + base::SysNSStringToUTF16(field.value)); // This should not happen in Payment Request. if (issuerNetwork == autofill::kGenericCard) return nil; @@ -186,40 +188,40 @@ ? [NSString stringWithFormat:@"%04d", _creditCard->expiration_year()] : nil; - NSMutableArray* editorFields = [[NSMutableArray alloc] init]; - [editorFields addObjectsFromArray:@[ + return @[ [[EditorField alloc] - initWithAutofillUIType:AutofillUITypeFromAutofillType( - autofill::CREDIT_CARD_NUMBER) + initWithAutofillUIType:AutofillUITypeCreditCardNumber fieldType:EditorFieldTypeTextField label:l10n_util::GetNSString(IDS_PAYMENTS_CARD_NUMBER) value:creditCardNumber required:YES], [[EditorField alloc] - initWithAutofillUIType:AutofillUITypeFromAutofillType( - autofill::CREDIT_CARD_NAME_FULL) + initWithAutofillUIType:AutofillUITypeCreditCardHolderFullName fieldType:EditorFieldTypeTextField label:l10n_util::GetNSString(IDS_PAYMENTS_NAME_ON_CARD) value:creditCardName required:YES], [[EditorField alloc] - initWithAutofillUIType:AutofillUITypeFromAutofillType( - autofill::CREDIT_CARD_EXP_MONTH) + initWithAutofillUIType:AutofillUITypeCreditCardExpMonth fieldType:EditorFieldTypeTextField label:l10n_util::GetNSString(IDS_PAYMENTS_EXP_MONTH) value:creditCardExpMonth required:YES], [[EditorField alloc] - initWithAutofillUIType:AutofillUITypeFromAutofillType( - autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR) + initWithAutofillUIType:AutofillUITypeCreditCardExpYear fieldType:EditorFieldTypeTextField label:l10n_util::GetNSString(IDS_PAYMENTS_EXP_YEAR) value:creditCardExpYear - required:YES] - ]]; - // The billing address field goes at the end. - [editorFields addObject:billingAddressEditorField]; - return editorFields; + required:YES], + billingAddressEditorField, + [[EditorField alloc] + initWithAutofillUIType:AutofillUITypeCreditCardSaveToChrome + fieldType:EditorFieldTypeSwitch + label:l10n_util::GetNSString( + IDS_PAYMENTS_SAVE_CARD_TO_DEVICE_CHECKBOX) + value:@"YES" + required:YES], + ]; } @end
diff --git a/ios/chrome/browser/ui/payments/credit_card_edit_view_controller.h b/ios/chrome/browser/ui/payments/credit_card_edit_view_controller.h deleted file mode 100644 index 0073807bd..0000000 --- a/ios/chrome/browser/ui/payments/credit_card_edit_view_controller.h +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_PAYMENTS_CREDIT_CARD_EDIT_VIEW_CONTROLLER_H_ -#define IOS_CHROME_BROWSER_UI_PAYMENTS_CREDIT_CARD_EDIT_VIEW_CONTROLLER_H_ - -#import "ios/chrome/browser/ui/payments/credit_card_edit_view_controller_data_source.h" -#import "ios/chrome/browser/ui/payments/payment_request_edit_view_controller.h" - -@class CreditCardEditViewController; - -// Delegate protocol for CreditCardEditViewController. -@protocol CreditCardEditViewControllerDelegate< - PaymentRequestEditViewControllerDelegate> - -// Notifies the delegate that the user has finished editing the credit card -// editor fields. -- (void)creditCardEditViewController:(CreditCardEditViewController*)controller - didFinishEditingFields:(NSArray<EditorField*>*)fields - saveCreditCard:(BOOL)saveCard; - -// Notifies the delegate that the user has chosen to discard entries in the -// credit card editor fields and return to the previous screen. -- (void)creditCardEditViewControllerDidCancel: - (CreditCardEditViewController*)controller; - -@end - -// View controller responsible for presenting a credit card edit form. The form -// features text fields for the field definitions passed to the initializer in -// addition to an item displaying the billing address associated with the credit -// card, if any. -@interface CreditCardEditViewController : PaymentRequestEditViewController - -// The delegate to be notified when the user returns or finishes editing the -// credit card editor fields. -@property(nonatomic, weak) id<CreditCardEditViewControllerDelegate> delegate; - -// The data source for this view controller. -@property(nonatomic, weak) id<CreditCardEditViewControllerDataSource> - dataSource; - -@end - -#endif // IOS_CHROME_BROWSER_UI_PAYMENTS_CREDIT_CARD_EDIT_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/payments/credit_card_edit_view_controller.mm b/ios/chrome/browser/ui/payments/credit_card_edit_view_controller.mm deleted file mode 100644 index 79b8ce4..0000000 --- a/ios/chrome/browser/ui/payments/credit_card_edit_view_controller.mm +++ /dev/null
@@ -1,213 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/ui/payments/credit_card_edit_view_controller.h" - -#import "base/mac/foundation_util.h" -#include "base/memory/ptr_util.h" -#include "components/strings/grit/components_strings.h" -#import "ios/chrome/browser/ui/autofill/autofill_ui_type.h" -#import "ios/chrome/browser/ui/autofill/cells/autofill_edit_item.h" -#import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h" -#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item+collection_view_controller.h" -#import "ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item.h" -#import "ios/chrome/browser/ui/collection_view/collection_view_model.h" -#import "ios/chrome/browser/ui/payments/payment_request_edit_view_controller+internal.h" -#import "ios/chrome/browser/ui/payments/payment_request_editor_field.h" -#import "ios/chrome/browser/ui/uikit_ui_util.h" -#include "ui/base/l10n/l10n_util.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -namespace { - -NSString* const kCreditCardEditCollectionViewId = - @"kCreditCardEditCollectionViewId"; - -typedef NS_ENUM(NSInteger, SectionIdentifier) { - SectionIdentifierSaveCard = kSectionIdentifierEnumStart, -}; - -typedef NS_ENUM(NSInteger, ItemType) { - ItemTypeSaveCard = kItemTypeEnumStart, -}; - -} // namespace - -@interface CreditCardEditViewController () { - // Indicates whether the credit card being created should be saved locally. - BOOL _saveCreditCard; -} - -// The list of field definitions for the editor. -@property(nonatomic, strong) NSArray<EditorField*>* fields; - -@end - -@implementation CreditCardEditViewController - -@synthesize delegate = _delegate; -@synthesize dataSource = _dataSource; -@synthesize fields = _fields; - -#pragma mark - Setters - -- (void)setDelegate:(id<CreditCardEditViewControllerDelegate>)delegate { - [super setDelegate:delegate]; - _delegate = delegate; -} - -- (void)setDataSource:(id<CreditCardEditViewControllerDataSource>)dataSource { - [super setDataSource:dataSource]; - _dataSource = dataSource; -} - -#pragma mark - PaymentRequestEditViewControllerActions methods - -- (void)onCancel { - [super onCancel]; - - [_delegate creditCardEditViewControllerDidCancel:self]; -} - -- (void)onDone { - [super onDone]; - - if (![self validateForm]) - return; - - [_delegate creditCardEditViewController:self - didFinishEditingFields:_fields - saveCreditCard:_saveCreditCard]; -} - -#pragma mark - CollectionViewController methods - -- (void)loadModel { - [super loadModel]; - - // If editing a credit card, set the card type icon (e.g. "Visa"). - if (_dataSource.state == EditViewControllerStateEdit) { - for (EditorField* field in _fields) { - if (field.autofillUIType == AutofillUITypeCreditCardNumber) { - AutofillEditItem* item = - base::mac::ObjCCastStrict<AutofillEditItem>(field.item); - item.identifyingIcon = - [_dataSource cardTypeIconFromCardNumber:item.textFieldValue]; - } - } - } -} - -- (void)loadFooterItems { - CollectionViewModel* model = self.collectionViewModel; - - // "Save card" section. Visible only when creating a card. - if (_dataSource.state == EditViewControllerStateCreate) { - [model addSectionWithIdentifier:SectionIdentifierSaveCard]; - CollectionViewSwitchItem* saveCardItem = - [[CollectionViewSwitchItem alloc] initWithType:ItemTypeSaveCard]; - saveCardItem.text = - l10n_util::GetNSString(IDS_PAYMENTS_SAVE_CARD_TO_DEVICE_CHECKBOX); - saveCardItem.on = YES; - [model addItem:saveCardItem - toSectionWithIdentifier:SectionIdentifierSaveCard]; - } - - [super loadFooterItems]; -} - -#pragma mark - UITextFieldDelegate - -// This method is called as the text is being typed in, pasted, or deleted. Asks -// the delegate if the text should be changed. Should always return YES. During -// typing/pasting text, |newText| contains one or more new characters. When user -// deletes text, |newText| is empty. |range| is the range of characters to be -// replaced. -- (BOOL)textField:(UITextField*)textField - shouldChangeCharactersInRange:(NSRange)range - replacementString:(NSString*)newText { - NSIndexPath* indexPath = [self indexPathForCurrentTextField]; - AutofillEditItem* item = base::mac::ObjCCastStrict<AutofillEditItem>( - [self.collectionViewModel itemAtIndexPath:indexPath]); - - // If the user is typing in the credit card number field, update the card type - // icon (e.g. "Visa") to reflect the number being typed. - if (item.autofillUIType == AutofillUITypeCreditCardNumber) { - // Obtain the text being typed. - NSString* updatedText = - [textField.text stringByReplacingCharactersInRange:range - withString:newText]; - item.identifyingIcon = [_dataSource cardTypeIconFromCardNumber:updatedText]; - - // Update the cell. - [self reconfigureCellsForItems:@[ item ]]; - } - - return YES; -} - -#pragma mark - UICollectionViewDataSource - -- (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView - cellForItemAtIndexPath:(NSIndexPath*)indexPath { - UICollectionViewCell* cell = - [super collectionView:collectionView cellForItemAtIndexPath:indexPath]; - CollectionViewItem* item = - [self.collectionViewModel itemAtIndexPath:indexPath]; - - switch (item.type) { - case ItemTypeSaveCard: { - CollectionViewSwitchCell* switchCell = - base::mac::ObjCCastStrict<CollectionViewSwitchCell>(cell); - [switchCell.switchView addTarget:self - action:@selector(saveCardSwitchToggled:) - forControlEvents:UIControlEventValueChanged]; - break; - } - default: - break; - } - - return cell; -} - -#pragma mark MDCCollectionViewStylingDelegate - -- (CGFloat)collectionView:(UICollectionView*)collectionView - cellHeightAtIndexPath:(NSIndexPath*)indexPath { - CollectionViewItem* item = - [self.collectionViewModel itemAtIndexPath:indexPath]; - switch (item.type) { - case ItemTypeSaveCard: - return [MDCCollectionViewCell - cr_preferredHeightForWidth:CGRectGetWidth(collectionView.bounds) - forItem:item]; - default: - return - [super collectionView:collectionView cellHeightAtIndexPath:indexPath]; - } -} - -- (BOOL)collectionView:(UICollectionView*)collectionView - hidesInkViewAtIndexPath:(NSIndexPath*)indexPath { - NSInteger type = [self.collectionViewModel itemTypeForIndexPath:indexPath]; - switch (type) { - case ItemTypeSaveCard: - return YES; - default: - return [super collectionView:collectionView - hidesInkViewAtIndexPath:indexPath]; - } -} - -#pragma mark Switch Actions - -- (void)saveCardSwitchToggled:(UISwitch*)sender { - _saveCreditCard = sender.isOn; -} - -@end
diff --git a/ios/chrome/browser/ui/payments/credit_card_edit_view_controller_data_source.h b/ios/chrome/browser/ui/payments/credit_card_edit_view_controller_data_source.h deleted file mode 100644 index 406aca340..0000000 --- a/ios/chrome/browser/ui/payments/credit_card_edit_view_controller_data_source.h +++ /dev/null
@@ -1,21 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_PAYMENTS_CREDIT_CARD_EDIT_VIEW_CONTROLLER_DATA_SOURCE_H_ -#define IOS_CHROME_BROWSER_UI_PAYMENTS_CREDIT_CARD_EDIT_VIEW_CONTROLLER_DATA_SOURCE_H_ - -#import <UIKit/UIKit.h> - -#import "ios/chrome/browser/ui/payments/payment_request_edit_view_controller_data_source.h" - -// Data source protocol for CreditCardEditViewController. -@protocol CreditCardEditViewControllerDataSource< - PaymentRequestEditViewControllerDataSource> - -// Returns the credit card type icon corresponding to |cardNumber|. -- (UIImage*)cardTypeIconFromCardNumber:(NSString*)cardNumber; - -@end - -#endif // IOS_CHROME_BROWSER_UI_PAYMENTS_CREDIT_CARD_EDIT_VIEW_CONTROLLER_DATA_SOURCE_H_
diff --git a/ios/chrome/browser/ui/payments/credit_card_edit_view_controller_unittest.mm b/ios/chrome/browser/ui/payments/credit_card_edit_view_controller_unittest.mm deleted file mode 100644 index 12f04c8..0000000 --- a/ios/chrome/browser/ui/payments/credit_card_edit_view_controller_unittest.mm +++ /dev/null
@@ -1,181 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/ui/payments/credit_card_edit_view_controller.h" - -#include "base/mac/foundation_util.h" -#include "base/memory/ptr_util.h" -#include "components/autofill/core/browser/field_types.h" -#include "ios/chrome/browser/payments/payment_request_test_util.h" -#import "ios/chrome/browser/ui/autofill/autofill_ui_type.h" -#import "ios/chrome/browser/ui/autofill/cells/autofill_edit_item.h" -#import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.h" -#import "ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item.h" -#import "ios/chrome/browser/ui/collection_view/cells/test_utils.h" -#import "ios/chrome/browser/ui/collection_view/collection_view_controller_test.h" -#import "ios/chrome/browser/ui/payments/cells/accepted_payment_methods_item.h" -#import "ios/chrome/browser/ui/payments/cells/payment_method_item.h" -#import "ios/chrome/browser/ui/payments/cells/payments_selector_edit_item.h" -#import "ios/chrome/browser/ui/payments/payment_request_edit_consumer.h" -#import "ios/chrome/browser/ui/payments/payment_request_editor_field.h" -#include "ios/web/public/payments/payment_request.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -@interface TestCreditCardEditViewControllerMediator - : NSObject<CreditCardEditViewControllerDataSource> - -@property(nonatomic, weak) id<PaymentRequestEditConsumer> consumer; - -@end - -@implementation TestCreditCardEditViewControllerMediator - -@synthesize state = _state; -@synthesize consumer = _consumer; - -- (CollectionViewItem*)headerItem { - return [[PaymentMethodItem alloc] init]; -} - -- (BOOL)shouldHideBackgroundForHeaderItem { - return NO; -} - -- (void)setConsumer:(id<PaymentRequestEditConsumer>)consumer { - _consumer = consumer; - [self.consumer setEditorFields:@[ - [[EditorField alloc] initWithAutofillUIType:AutofillUITypeCreditCardNumber - fieldType:EditorFieldTypeTextField - label:@"Credit Card Number" - value:@"4111111111111111" /* Visa */ - required:YES], - [[EditorField alloc] - initWithAutofillUIType:AutofillUITypeCreditCardHolderFullName - fieldType:EditorFieldTypeTextField - label:@"Cardholder Name" - value:@"John Doe" - required:YES], - [[EditorField alloc] initWithAutofillUIType:AutofillUITypeCreditCardExpMonth - fieldType:EditorFieldTypeTextField - label:@"Expiration Month" - value:@"12" - required:YES], - [[EditorField alloc] initWithAutofillUIType:AutofillUITypeCreditCardExpYear - fieldType:EditorFieldTypeTextField - label:@"Expiration Year" - value:@"2090" - required:YES], - [[EditorField alloc] - initWithAutofillUIType:AutofillUITypeCreditCardBillingAddress - fieldType:EditorFieldTypeSelector - label:@"Billing Address" - value:@"12345" - required:YES], - ]]; -} - -- (UIImage*)cardTypeIconFromCardNumber:(NSString*)cardNumber { - return nil; -} - -@end - -class PaymentRequestCreditCardEditViewControllerTest - : public CollectionViewControllerTest { - protected: - CollectionViewController* InstantiateController() override { - CreditCardEditViewController* viewController = - [[CreditCardEditViewController alloc] init]; - mediator_ = [[TestCreditCardEditViewControllerMediator alloc] init]; - [mediator_ setConsumer:viewController]; - [viewController setDataSource:mediator_]; - return viewController; - } - - CreditCardEditViewController* GetCreditCardEditViewController() { - return base::mac::ObjCCastStrict<CreditCardEditViewController>( - controller()); - } - - TestCreditCardEditViewControllerMediator* mediator_ = nil; -}; - -// Tests that the correct number of items are displayed after loading the model. -TEST_F(PaymentRequestCreditCardEditViewControllerTest, TestModel) { - CreateController(); - CheckController(); - - [mediator_ setState:EditViewControllerStateEdit]; - [GetCreditCardEditViewController() loadModel]; - - // There is one section containing the credit card type icons for the accepted - // payment methods. In addition to that, there is one section for every field - // (there are five form fields in total), and finally one for the footer. - ASSERT_EQ(7, NumberOfSections()); - - // The server card summary section is the first section and has one item of - // the type PaymentMethodItem. - ASSERT_EQ(1U, static_cast<unsigned int>(NumberOfItemsInSection(0))); - id item = GetCollectionViewItem(0, 0); - EXPECT_TRUE([item isMemberOfClass:[PaymentMethodItem class]]); - - // The next four sections have only one item of the type AutofillEditItem. - ASSERT_EQ(1U, static_cast<unsigned int>(NumberOfItemsInSection(1))); - item = GetCollectionViewItem(1, 0); - EXPECT_TRUE([item isMemberOfClass:[AutofillEditItem class]]); - - ASSERT_EQ(1U, static_cast<unsigned int>(NumberOfItemsInSection(2))); - item = GetCollectionViewItem(2, 0); - EXPECT_TRUE([item isMemberOfClass:[AutofillEditItem class]]); - - ASSERT_EQ(1U, static_cast<unsigned int>(NumberOfItemsInSection(3))); - item = GetCollectionViewItem(3, 0); - EXPECT_TRUE([item isMemberOfClass:[AutofillEditItem class]]); - - ASSERT_EQ(1U, static_cast<unsigned int>(NumberOfItemsInSection(4))); - item = GetCollectionViewItem(4, 0); - EXPECT_TRUE([item isMemberOfClass:[AutofillEditItem class]]); - - // The billing address section contains one item which is of the type - // PaymentsSelectorEditItem. - ASSERT_EQ(1U, static_cast<unsigned int>(NumberOfItemsInSection(5))); - item = GetCollectionViewItem(5, 0); - EXPECT_TRUE([item isMemberOfClass:[PaymentsSelectorEditItem class]]); - PaymentsSelectorEditItem* billing_address_item = item; - EXPECT_EQ(MDCCollectionViewCellAccessoryDisclosureIndicator, - billing_address_item.accessoryType); - - // The footer section contains one item which is of the type - // CollectionViewFooterItem. - ASSERT_EQ(1U, static_cast<unsigned int>(NumberOfItemsInSection(6))); - item = GetCollectionViewItem(6, 0); - EXPECT_TRUE([item isMemberOfClass:[CollectionViewFooterItem class]]); -} - -// Tests that the correct number of items are displayed after loading the model, -// when creating a new credit card. -TEST_F(PaymentRequestCreditCardEditViewControllerTest, - TestModelCreateNewCreditCard) { - CreateController(); - CheckController(); - - [mediator_ setState:EditViewControllerStateCreate]; - [GetCreditCardEditViewController() loadModel]; - - // There is an extra section containing a switch that allows the user to save - // the credit card locally. - ASSERT_EQ(8, NumberOfSections()); - - // The switch section is the last section before the footer and has one item - // of the type CollectionViewSwitchItem. The switch is on by defualt. - ASSERT_EQ(1U, static_cast<unsigned int>(NumberOfItemsInSection(6))); - id item = GetCollectionViewItem(6, 0); - EXPECT_TRUE([item isMemberOfClass:[CollectionViewSwitchItem class]]); - CollectionViewSwitchItem* switch_item = item; - EXPECT_EQ(YES, [switch_item isOn]); -}
diff --git a/ios/chrome/browser/ui/payments/payment_request_edit_view_controller+internal.h b/ios/chrome/browser/ui/payments/payment_request_edit_view_controller+internal.h deleted file mode 100644 index beed7be..0000000 --- a/ios/chrome/browser/ui/payments/payment_request_edit_view_controller+internal.h +++ /dev/null
@@ -1,38 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_PAYMENTS_PAYMENT_REQUEST_EDIT_VIEW_CONTROLLER_INTERNAL_H_ -#define IOS_CHROME_BROWSER_UI_PAYMENTS_PAYMENT_REQUEST_EDIT_VIEW_CONTROLLER_INTERNAL_H_ - -#import "ios/chrome/browser/ui/payments/payment_request_edit_view_controller.h" -#import "ios/chrome/browser/ui/payments/payment_request_edit_view_controller_actions.h" - -// Use these as the starting values for section identifier and item type enums -// in subclasses. These values are chosen to prevent overlapping with the -// section identifier and item type enums of this class. -const NSInteger kSectionIdentifierEnumStart = kSectionIdentifierEnumZero + 20; -const NSInteger kItemTypeEnumStart = kItemTypeEnumZero + 100; - -// Internal API for subclasses of PaymentRequestEditViewController. -@interface PaymentRequestEditViewController ( - Internal)<PaymentRequestEditViewControllerActions> - -// Validates each field. If there is a validation error, displays an error -// message item in the same section as the field and returns NO. Otherwise -// removes the error message item in that section if one exists and sets the -// value on the field. Returns YES if all the fields are validated successfully. -- (BOOL)validateForm; - -// Called after the editor field items have been added to the the collection -// view model. Subclasses override this method to add items after the editor -// fields. -- (void)loadFooterItems; - -// Returns the index path for the cell associated with the currently focused -// text field. -- (NSIndexPath*)indexPathForCurrentTextField; - -@end - -#endif // IOS_CHROME_BROWSER_UI_PAYMENTS_PAYMENT_REQUEST_EDIT_VIEW_CONTROLLER_INTERNAL_H_
diff --git a/ios/chrome/browser/ui/payments/payment_request_edit_view_controller.h b/ios/chrome/browser/ui/payments/payment_request_edit_view_controller.h index bc1c271..4352f8e 100644 --- a/ios/chrome/browser/ui/payments/payment_request_edit_view_controller.h +++ b/ios/chrome/browser/ui/payments/payment_request_edit_view_controller.h
@@ -26,6 +26,16 @@ (PaymentRequestEditViewController*)controller didSelectField:(EditorField*)field; +// Notifies the delegate that the user has finished editing the editor fields. +- (void)paymentRequestEditViewController: + (PaymentRequestEditViewController*)controller + didFinishEditingFields:(NSArray<EditorField*>*)fields; + +// Notifies the delegate that the user has chosen to discard entries in the +// editor fields and return to the previous screen. +- (void)paymentRequestEditViewControllerDidCancel: + (PaymentRequestEditViewController*)controller; + @end // Validator protocol for PaymentRequestEditViewController.
diff --git a/ios/chrome/browser/ui/payments/payment_request_edit_view_controller.mm b/ios/chrome/browser/ui/payments/payment_request_edit_view_controller.mm index 0e58eb9..9539bc97 100644 --- a/ios/chrome/browser/ui/payments/payment_request_edit_view_controller.mm +++ b/ios/chrome/browser/ui/payments/payment_request_edit_view_controller.mm
@@ -13,10 +13,11 @@ #import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h" #import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.h" #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item+collection_view_controller.h" +#import "ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item.h" #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h" #import "ios/chrome/browser/ui/payments/cells/payments_selector_edit_item.h" #import "ios/chrome/browser/ui/payments/cells/payments_text_item.h" -#import "ios/chrome/browser/ui/payments/payment_request_edit_view_controller+internal.h" +#import "ios/chrome/browser/ui/payments/payment_request_edit_view_controller_actions.h" #import "ios/chrome/browser/ui/payments/payment_request_editor_field.h" #import "ios/chrome/browser/ui/uikit_ui_util.h" #include "ios/chrome/grit/ios_theme_resources.h" @@ -52,6 +53,20 @@ return nil; } +CollectionViewSwitchCell* CollectionViewSwitchCellForSwitchField( + UISwitch* switchField) { + for (UIView* view = switchField; view; view = [view superview]) { + CollectionViewSwitchCell* cell = + base::mac::ObjCCast<CollectionViewSwitchCell>(view); + if (cell) + return cell; + } + + // There should be a cell associated with this switch field. + NOTREACHED(); + return nil; +} + typedef NS_ENUM(NSInteger, SectionIdentifier) { SectionIdentifierHeader = kSectionIdentifierEnumZero, SectionIdentifierFooter, @@ -63,22 +78,25 @@ ItemTypeFooter, ItemTypeTextField, // This is a repeated item type. ItemTypeSelectorField, // This is a repeated item type. + ItemTypeSwitchField, // This is a repeated item type. ItemTypeErrorMessage, // This is a repeated item type. }; } // namespace -@interface PaymentRequestEditViewController ()<AutofillEditAccessoryDelegate, - UITextFieldDelegate, - UIPickerViewDataSource, - UIPickerViewDelegate> { +@interface PaymentRequestEditViewController ()< + AutofillEditAccessoryDelegate, + PaymentRequestEditViewControllerActions, + UIPickerViewDataSource, + UIPickerViewDelegate, + UITextFieldDelegate> { // The currently focused cell. May be nil. __weak AutofillEditCell* _currentEditingCell; AutofillEditAccessoryView* _accessoryView; } -// The map of autofill types to the fields definitions for the editor. +// The map of section identifiers to the fields definitions for the editor. @property(nonatomic, strong) NSMutableDictionary<NSNumber*, EditorField*>* fieldsMap; @@ -112,6 +130,16 @@ - (void)addOrRemoveErrorMessage:(NSString*)errorMessage inSectionWithIdentifier:(NSInteger)sectionIdentifier; +// Validates each field. If there is a validation error, displays an error +// message item in the same section as the field and returns NO. Otherwise +// removes the error message item in that section if one exists and sets the +// value on the field. Returns YES if all the fields are validated successfully. +- (BOOL)validateForm; + +// Returns the index path for the cell associated with the currently focused +// text field. +- (NSIndexPath*)indexPathForCurrentTextField; + @end @implementation PaymentRequestEditViewController @@ -200,6 +228,9 @@ [model addItem:headerItem toSectionWithIdentifier:SectionIdentifierHeader]; } + self.fieldsMap = + [[NSMutableDictionary alloc] initWithCapacity:self.fields.count]; + // Iterate over the fields and add the respective sections and items. [self.fields enumerateObjectsUsingBlock:^(EditorField* field, NSUInteger index, BOOL* stop) { @@ -214,6 +245,7 @@ item.textFieldValue = field.value; item.required = field.isRequired; item.autofillUIType = field.autofillUIType; + item.identifyingIcon = [_dataSource iconIdentifyingEditorField:field]; [model addItem:item toSectionWithIdentifier:sectionIdentifier]; field.item = item; @@ -231,14 +263,29 @@ field.item = item; break; } + case EditorFieldTypeSwitch: { + CollectionViewSwitchItem* item = + [[CollectionViewSwitchItem alloc] initWithType:ItemTypeSwitchField]; + item.text = field.label; + item.on = [field.value boolValue]; + [model addItem:item toSectionWithIdentifier:sectionIdentifier]; + field.item = item; + break; + } default: NOTREACHED(); } field.sectionIdentifier = sectionIdentifier; + NSNumber* key = [NSNumber numberWithInt:sectionIdentifier]; + [self.fieldsMap setObject:field forKey:key]; }]; - [self loadFooterItems]; + [model addSectionWithIdentifier:SectionIdentifierFooter]; + CollectionViewFooterItem* footerItem = + [[CollectionViewFooterItem alloc] initWithType:ItemTypeFooter]; + footerItem.text = l10n_util::GetNSString(IDS_PAYMENTS_REQUIRED_FIELD_MESSAGE); + [model addItem:footerItem toSectionWithIdentifier:SectionIdentifierFooter]; } - (void)viewDidLoad { @@ -257,13 +304,6 @@ - (void)setEditorFields:(NSArray<EditorField*>*)fields { self.fields = fields; - self.fieldsMap = [[NSMutableDictionary alloc] initWithCapacity:fields.count]; - // Iterate over the fields and populate the map. - [self.fields enumerateObjectsUsingBlock:^(EditorField* field, - NSUInteger index, BOOL* stop) { - NSNumber* key = [NSNumber numberWithInt:field.autofillUIType]; - [self.fieldsMap setObject:field forKey:key]; - }]; } - (void)setOptions:(NSArray<NSString*>*)options @@ -304,22 +344,18 @@ - (void)textFieldDidEndEditing:(UITextField*)textField { DCHECK(_currentEditingCell == AutofillEditCellForTextField(textField)); - CollectionViewModel* model = self.collectionViewModel; - NSIndexPath* indexPath = [self indexPathForCurrentTextField]; - AutofillEditItem* item = base::mac::ObjCCastStrict<AutofillEditItem>( - [model itemAtIndexPath:indexPath]); + NSInteger sectionIdentifier = [self.collectionViewModel + sectionIdentifierForSection:[indexPath section]]; - // Find and validate the respective editor field. - NSNumber* key = [NSNumber numberWithInt:item.autofillUIType]; + // Find the respective editor field, update its value, and validate it. + NSNumber* key = [NSNumber numberWithInt:sectionIdentifier]; EditorField* field = self.fieldsMap[key]; DCHECK(field); field.value = textField.text; NSString* errorMessage = [_validatorDelegate paymentRequestEditViewController:self validateField:field]; - NSInteger sectionIdentifier = - [model sectionIdentifierForSection:[indexPath section]]; [self addOrRemoveErrorMessage:errorMessage inSectionWithIdentifier:sectionIdentifier]; @@ -338,6 +374,44 @@ return NO; } +// This method is called as the text is being typed in, pasted, or deleted. Asks +// the delegate if the text should be changed. Should always return YES. During +// typing/pasting text, |newText| contains one or more new characters. When user +// deletes text, |newText| is empty. |range| is the range of characters to be +// replaced. +- (BOOL)textField:(UITextField*)textField + shouldChangeCharactersInRange:(NSRange)range + replacementString:(NSString*)newText { + CollectionViewModel* model = self.collectionViewModel; + + DCHECK(_currentEditingCell == AutofillEditCellForTextField(textField)); + + NSIndexPath* indexPath = [self indexPathForCurrentTextField]; + NSInteger sectionIdentifier = + [model sectionIdentifierForSection:[indexPath section]]; + AutofillEditItem* item = base::mac::ObjCCastStrict<AutofillEditItem>( + [model itemAtIndexPath:indexPath]); + + // Find the respective editor field and update its value. + NSNumber* key = [NSNumber numberWithInt:sectionIdentifier]; + EditorField* field = self.fieldsMap[key]; + DCHECK(field); + // Obtain the text being typed. + NSString* updatedText = + [textField.text stringByReplacingCharactersInRange:range + withString:newText]; + field.value = updatedText; + + // Get the icon that identifies the field value and reload the cell if the + // icon changes. + UIImage* oldIcon = item.identifyingIcon; + item.identifyingIcon = [_dataSource iconIdentifyingEditorField:field]; + if (item.identifyingIcon != oldIcon) + [self reconfigureCellsForItems:@[ item ]]; + + return YES; +} + #pragma mark - AutofillEditAccessoryDelegate - (void)nextPressed { @@ -414,6 +488,14 @@ [[MDCPalette cr_bluePalette] tint600]; break; } + case ItemTypeSwitchField: { + CollectionViewSwitchCell* switchCell = + base::mac::ObjCCastStrict<CollectionViewSwitchCell>(cell); + [switchCell.switchView addTarget:self + action:@selector(switchToggled:) + forControlEvents:UIControlEventValueChanged]; + break; + } case ItemTypeErrorMessage: { PaymentsTextCell* errorMessageCell = base::mac::ObjCCastStrict<PaymentsTextCell>(cell); @@ -471,6 +553,7 @@ case ItemTypeHeader: case ItemTypeFooter: case ItemTypeTextField: + case ItemTypeSwitchField: case ItemTypeErrorMessage: return [MDCCollectionViewCell cr_preferredHeightForWidth:CGRectGetWidth(collectionView.bounds) @@ -490,6 +573,8 @@ case ItemTypeHeader: case ItemTypeFooter: case ItemTypeErrorMessage: + case ItemTypeTextField: + case ItemTypeSwitchField: return YES; default: return NO; @@ -582,20 +667,6 @@ } } -#pragma mark - Keyboard handling - -- (void)keyboardDidShow { - [self.collectionView - scrollToItemAtIndexPath:[self.collectionView - indexPathForCell:_currentEditingCell] - atScrollPosition:UICollectionViewScrollPositionCenteredVertically - animated:YES]; -} - -@end - -@implementation PaymentRequestEditViewController (Internal) - - (BOOL)validateForm { for (EditorField* field in self.fields) { NSString* errorMessage = @@ -609,16 +680,6 @@ return YES; } -- (void)loadFooterItems { - CollectionViewModel* model = self.collectionViewModel; - - [model addSectionWithIdentifier:SectionIdentifierFooter]; - CollectionViewFooterItem* footerItem = - [[CollectionViewFooterItem alloc] initWithType:ItemTypeFooter]; - footerItem.text = l10n_util::GetNSString(IDS_PAYMENTS_REQUIRED_FIELD_MESSAGE); - [model addItem:footerItem toSectionWithIdentifier:SectionIdentifierFooter]; -} - - (NSIndexPath*)indexPathForCurrentTextField { DCHECK(_currentEditingCell); NSIndexPath* indexPath = @@ -627,13 +688,48 @@ return indexPath; } +#pragma mark - Keyboard handling + +- (void)keyboardDidShow { + [self.collectionView + scrollToItemAtIndexPath:[self.collectionView + indexPathForCell:_currentEditingCell] + atScrollPosition:UICollectionViewScrollPositionCenteredVertically + animated:YES]; +} + +#pragma mark Switch Actions + +- (void)switchToggled:(UISwitch*)sender { + CollectionViewSwitchCell* switchCell = + CollectionViewSwitchCellForSwitchField(sender); + NSIndexPath* indexPath = [[self collectionView] indexPathForCell:switchCell]; + DCHECK(indexPath); + + NSInteger sectionIdentifier = [self.collectionViewModel + sectionIdentifierForSection:[indexPath section]]; + + // Update editor field's value. + NSNumber* key = [NSNumber numberWithInt:sectionIdentifier]; + EditorField* field = self.fieldsMap[key]; + DCHECK(field); + field.value = [sender isOn] ? @"YES" : @"NO"; +} + #pragma mark - PaymentRequestEditViewControllerActions methods - (void)onCancel { + [self.delegate paymentRequestEditViewControllerDidCancel:self]; } - (void)onDone { [_currentEditingCell.textField resignFirstResponder]; + + if (![self validateForm]) + return; + + [self.delegate paymentRequestEditViewController:self + didFinishEditingFields:self.fields]; } @end
diff --git a/ios/chrome/browser/ui/payments/payment_request_edit_view_controller_data_source.h b/ios/chrome/browser/ui/payments/payment_request_edit_view_controller_data_source.h index 36ffd10..d3bc084 100644 --- a/ios/chrome/browser/ui/payments/payment_request_edit_view_controller_data_source.h +++ b/ios/chrome/browser/ui/payments/payment_request_edit_view_controller_data_source.h
@@ -5,7 +5,7 @@ #ifndef IOS_CHROME_BROWSER_UI_PAYMENTS_PAYMENT_REQUEST_EDIT_VIEW_CONTROLLER_DATA_SOURCE_H_ #define IOS_CHROME_BROWSER_UI_PAYMENTS_PAYMENT_REQUEST_EDIT_VIEW_CONTROLLER_DATA_SOURCE_H_ -#import <Foundation/Foundation.h> +#import <UIKit/UIKit.h> @class EditorField; @class CollectionViewItem; @@ -30,6 +30,9 @@ // Returns whether the header item should hide its background. - (BOOL)shouldHideBackgroundForHeaderItem; +// Returns an icon that identifies |field| or its current value. May be nil. +- (UIImage*)iconIdentifyingEditorField:(EditorField*)field; + @end #endif // IOS_CHROME_BROWSER_UI_PAYMENTS_PAYMENT_REQUEST_EDIT_VIEW_CONTROLLER_DATA_SOURCE_H_
diff --git a/ios/chrome/browser/ui/payments/payment_request_edit_view_controller_unittest.mm b/ios/chrome/browser/ui/payments/payment_request_edit_view_controller_unittest.mm index f35e3df8..21524ff4 100644 --- a/ios/chrome/browser/ui/payments/payment_request_edit_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/payments/payment_request_edit_view_controller_unittest.mm
@@ -9,6 +9,7 @@ #import "ios/chrome/browser/ui/autofill/autofill_ui_type.h" #import "ios/chrome/browser/ui/autofill/cells/autofill_edit_item.h" #import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.h" +#import "ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item.h" #import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h" #import "ios/chrome/browser/ui/collection_view/collection_view_controller_test.h" #import "ios/chrome/browser/ui/payments/cells/payments_selector_edit_item.h" @@ -41,6 +42,10 @@ return NO; } +- (UIImage*)iconIdentifyingEditorField:(EditorField*)field { + return nil; +} + - (void)setConsumer:(id<PaymentRequestEditConsumer>)consumer { _consumer = consumer; [self.consumer setEditorFields:@[ @@ -54,6 +59,12 @@ label:@"" value:@"" required:YES], + [[EditorField alloc] + initWithAutofillUIType:AutofillUITypeCreditCardSaveToChrome + fieldType:EditorFieldTypeSwitch + label:@"" + value:@"YES" + required:YES], ]]; } @@ -88,9 +99,9 @@ [GetPaymentRequestEditViewController() loadModel]; // There is one section containing the header item, In addition to that, there - // is one section for every form field (there are two fields in total) and one - // for the footer. - ASSERT_EQ(4, NumberOfSections()); + // is one section for every form field (there are three fields in total) and + // one for the footer. + ASSERT_EQ(5, NumberOfSections()); // The header section is the first section and has one item of the type // CollectionViewTextItem. @@ -108,9 +119,14 @@ item = GetCollectionViewItem(2, 0); EXPECT_TRUE([item isMemberOfClass:[PaymentsSelectorEditItem class]]); + // The next section has one item of the type CollectionViewSwitchItem. + ASSERT_EQ(1U, static_cast<unsigned int>(NumberOfItemsInSection(3))); + item = GetCollectionViewItem(3, 0); + EXPECT_TRUE([item isMemberOfClass:[CollectionViewSwitchItem class]]); + // The footer section contains one item which is of the type // CollectionViewFooterItem. ASSERT_EQ(1U, static_cast<unsigned int>(NumberOfItemsInSection(3))); - item = GetCollectionViewItem(3, 0); + item = GetCollectionViewItem(4, 0); EXPECT_TRUE([item isMemberOfClass:[CollectionViewFooterItem class]]); }
diff --git a/ios/chrome/browser/ui/payments/payment_request_editor_field.h b/ios/chrome/browser/ui/payments/payment_request_editor_field.h index 8f54213..27c0c6a 100644 --- a/ios/chrome/browser/ui/payments/payment_request_editor_field.h +++ b/ios/chrome/browser/ui/payments/payment_request_editor_field.h
@@ -15,6 +15,7 @@ typedef NS_ENUM(NSInteger, EditorFieldType) { EditorFieldTypeTextField, EditorFieldTypeSelector, + EditorFieldTypeSwitch, }; // Field definition for an editor field. Used for building the UI and
diff --git a/ios/showcase/payments/sc_payments_editor_coordinator.mm b/ios/showcase/payments/sc_payments_editor_coordinator.mm index 1b5621e..7bd18082 100644 --- a/ios/showcase/payments/sc_payments_editor_coordinator.mm +++ b/ios/showcase/payments/sc_payments_editor_coordinator.mm
@@ -102,6 +102,10 @@ return NO; } +- (UIImage*)iconIdentifyingEditorField:(EditorField*)field { + return nil; +} + #pragma mark - PaymentRequestEditViewControllerValidator - (NSString*)paymentRequestEditViewController:
diff --git a/media/cast/test/utility/standalone_cast_environment.cc b/media/cast/test/utility/standalone_cast_environment.cc index 272f04d..9a2b4b2 100644 --- a/media/cast/test/utility/standalone_cast_environment.cc +++ b/media/cast/test/utility/standalone_cast_environment.cc
@@ -6,6 +6,7 @@ #include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" +#include "base/threading/thread_restrictions.h" #include "base/time/default_tick_clock.h" namespace media { @@ -40,6 +41,9 @@ void StandaloneCastEnvironment::Shutdown() { CHECK(CalledOnValidThread()); + + base::ThreadRestrictions::ScopedAllowIO + because_i_brought_you_into_this_world_and_i_am_gonna_take_you_out; main_thread_.Stop(); audio_thread_.Stop(); video_thread_.Stop();
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn index 9ae2be7..9a04f5b 100644 --- a/media/gpu/BUILD.gn +++ b/media/gpu/BUILD.gn
@@ -217,6 +217,8 @@ if (enable_media_codec_video_decoder) { assert(mojo_media_host == "gpu", "MCVD requires the CDM") sources += [ + "android/codec_wrapper.cc", + "android/codec_wrapper.h", "android/media_codec_video_decoder.cc", "android/media_codec_video_decoder.h", ] @@ -460,7 +462,10 @@ "surface_texture_gl_owner_unittest.cc", ] if (enable_media_codec_video_decoder) { - sources += [ "android/media_codec_video_decoder_unittest.cc" ] + sources += [ + "android/codec_wrapper_unittest.cc", + "android/media_codec_video_decoder_unittest.cc", + ] } deps = [ ":gpu",
diff --git a/media/gpu/android/codec_wrapper.cc b/media/gpu/android/codec_wrapper.cc new file mode 100644 index 0000000..c738a72 --- /dev/null +++ b/media/gpu/android/codec_wrapper.cc
@@ -0,0 +1,344 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/gpu/android/codec_wrapper.h" + +#include <stddef.h> +#include <stdint.h> + +#include <string> +#include <vector> + +#include "base/memory/ptr_util.h" +#include "base/stl_util.h" +#include "media/base/android/media_codec_util.h" + +namespace media { + +// CodecWrapperImpl is the implementation for CodecWrapper but is separate so +// we can keep its refcounting as an implementation detail. CodecWrapper and +// CodecOutputBuffer are the only two things that hold references to it. +class CodecWrapperImpl : public base::RefCountedThreadSafe<CodecWrapperImpl> { + public: + CodecWrapperImpl(std::unique_ptr<MediaCodecBridge> codec); + + std::unique_ptr<MediaCodecBridge> TakeCodec(); + bool HasValidCodecOutputBuffers() const; + void DiscardCodecOutputBuffers(); + bool SupportsFlush() const; + bool Flush(); + MediaCodecStatus QueueInputBuffer(int index, + const uint8_t* data, + size_t data_size, + base::TimeDelta presentation_time); + MediaCodecStatus QueueSecureInputBuffer( + int index, + const uint8_t* data, + size_t data_size, + const std::string& key_id, + const std::string& iv, + const std::vector<SubsampleEntry>& subsamples, + const EncryptionScheme& encryption_scheme, + base::TimeDelta presentation_time); + void QueueEOS(int input_buffer_index); + MediaCodecStatus DequeueInputBuffer(base::TimeDelta timeout, int* index); + MediaCodecStatus DequeueOutputBuffer( + base::TimeDelta timeout, + base::TimeDelta* presentation_time, + bool* end_of_stream, + std::unique_ptr<CodecOutputBuffer>* codec_buffer); + bool SetSurface(jobject surface); + + // Releases the codec buffer and optionally renders it. This is a noop if + // the codec buffer is not valid (i.e., there's no race between checking its + // validity and releasing it). Can be called on any thread. Returns true if + // the buffer was released. + bool ReleaseCodecOutputBuffer(int64_t id, bool render); + + private: + friend base::RefCountedThreadSafe<CodecWrapperImpl>; + ~CodecWrapperImpl(); + + void DiscardCodecOutputBuffers_Locked(); + + // |lock_| protects access to all member variables. + mutable base::Lock lock_; + std::unique_ptr<MediaCodecBridge> codec_; + bool in_error_state_; + + // Buffer ids are unique for a given CodecWrapper and map to MediaCodec buffer + // indices. + int64_t next_buffer_id_; + base::flat_map<int64_t, int> buffer_ids_; + + // The current output size. Updated when DequeueOutputBuffer() reports + // OUTPUT_FORMAT_CHANGED. + gfx::Size size_; + + DISALLOW_COPY_AND_ASSIGN(CodecWrapperImpl); +}; + +CodecOutputBuffer::CodecOutputBuffer(scoped_refptr<CodecWrapperImpl> codec, + int64_t id, + gfx::Size size) + : codec_(std::move(codec)), id_(id), size_(size) {} + +CodecOutputBuffer::~CodecOutputBuffer() { + codec_->ReleaseCodecOutputBuffer(id_, false); +} + +bool CodecOutputBuffer::ReleaseToSurface() { + return codec_->ReleaseCodecOutputBuffer(id_, true); +} + +CodecWrapperImpl::CodecWrapperImpl(std::unique_ptr<MediaCodecBridge> codec) + : codec_(std::move(codec)), in_error_state_(false), next_buffer_id_(0) {} + +CodecWrapperImpl::~CodecWrapperImpl() = default; + +std::unique_ptr<MediaCodecBridge> CodecWrapperImpl::TakeCodec() { + base::AutoLock l(lock_); + if (!codec_) + return nullptr; + DiscardCodecOutputBuffers_Locked(); + return std::move(codec_); +} + +bool CodecWrapperImpl::HasValidCodecOutputBuffers() const { + base::AutoLock l(lock_); + return !buffer_ids_.empty(); +} + +void CodecWrapperImpl::DiscardCodecOutputBuffers() { + base::AutoLock l(lock_); + DiscardCodecOutputBuffers_Locked(); +} + +void CodecWrapperImpl::DiscardCodecOutputBuffers_Locked() { + lock_.AssertAcquired(); + for (auto& kv : buffer_ids_) + codec_->ReleaseOutputBuffer(kv.second, false); + buffer_ids_.clear(); +} + +bool CodecWrapperImpl::SupportsFlush() const { + base::AutoLock l(lock_); + return !MediaCodecUtil::CodecNeedsFlushWorkaround(codec_.get()); +} + +bool CodecWrapperImpl::Flush() { + base::AutoLock l(lock_); + DCHECK(codec_ && !in_error_state_); + + // Dequeued output buffers are invalidated by flushing. + buffer_ids_.clear(); + auto status = codec_->Flush(); + if (status == MEDIA_CODEC_ERROR) { + in_error_state_ = true; + return false; + } + return true; +} + +MediaCodecStatus CodecWrapperImpl::QueueInputBuffer( + int index, + const uint8_t* data, + size_t data_size, + base::TimeDelta presentation_time) { + base::AutoLock l(lock_); + DCHECK(codec_ && !in_error_state_); + + auto status = + codec_->QueueInputBuffer(index, data, data_size, presentation_time); + if (status == MEDIA_CODEC_ERROR) + in_error_state_ = true; + return status; +} + +MediaCodecStatus CodecWrapperImpl::QueueSecureInputBuffer( + int index, + const uint8_t* data, + size_t data_size, + const std::string& key_id, + const std::string& iv, + const std::vector<SubsampleEntry>& subsamples, + const EncryptionScheme& encryption_scheme, + base::TimeDelta presentation_time) { + base::AutoLock l(lock_); + DCHECK(codec_ && !in_error_state_); + + auto status = codec_->QueueSecureInputBuffer( + index, data, data_size, key_id, iv, subsamples, encryption_scheme, + presentation_time); + if (status == MEDIA_CODEC_ERROR) + in_error_state_ = true; + return status; +} + +void CodecWrapperImpl::QueueEOS(int input_buffer_index) { + base::AutoLock l(lock_); + DCHECK(codec_ && !in_error_state_); + codec_->QueueEOS(input_buffer_index); +} + +MediaCodecStatus CodecWrapperImpl::DequeueInputBuffer(base::TimeDelta timeout, + int* index) { + base::AutoLock l(lock_); + DCHECK(codec_ && !in_error_state_); + auto status = codec_->DequeueInputBuffer(timeout, index); + if (status == MEDIA_CODEC_ERROR) + in_error_state_ = true; + return status; +} + +MediaCodecStatus CodecWrapperImpl::DequeueOutputBuffer( + base::TimeDelta timeout, + base::TimeDelta* presentation_time, + bool* end_of_stream, + std::unique_ptr<CodecOutputBuffer>* codec_buffer) { + base::AutoLock l(lock_); + DCHECK(codec_ && !in_error_state_); + // If |*codec_buffer| were not null, deleting it may deadlock when it + // tries to release itself. + DCHECK(!*codec_buffer); + + // Dequeue in a loop so we can avoid propagating the uninteresting + // OUTPUT_FORMAT_CHANGED and OUTPUT_BUFFERS_CHANGED statuses to our caller. + for (int attempt = 0; attempt < 3; ++attempt) { + int index = -1; + size_t unused_offset = 0; + size_t unused_size = 0; + bool* unused_key_frame = nullptr; + auto status = codec_->DequeueOutputBuffer(timeout, &index, &unused_offset, + &unused_size, presentation_time, + end_of_stream, unused_key_frame); + switch (status) { + case MEDIA_CODEC_OK: { + int64_t buffer_id = next_buffer_id_++; + buffer_ids_[buffer_id] = index; + *codec_buffer = + base::WrapUnique(new CodecOutputBuffer(this, buffer_id, size_)); + return status; + } + case MEDIA_CODEC_ERROR: { + in_error_state_ = true; + return status; + } + case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: { + // An OUTPUT_FORMAT_CHANGED is not reported after Flush() if the frame + // size does not change. + if (codec_->GetOutputSize(&size_) == MEDIA_CODEC_ERROR) { + in_error_state_ = true; + return MEDIA_CODEC_ERROR; + } + continue; + } + case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: + continue; + default: + return status; + } + } + + in_error_state_ = true; + return MEDIA_CODEC_ERROR; +} + +bool CodecWrapperImpl::SetSurface(jobject surface) { + base::AutoLock l(lock_); + DCHECK(codec_ && !in_error_state_); + + bool status = codec_->SetSurface(surface); + if (!status) + in_error_state_ = true; + return status; +} + +bool CodecWrapperImpl::ReleaseCodecOutputBuffer(int64_t id, bool render) { + base::AutoLock l(lock_); + if (!codec_ || in_error_state_) + return false; + + auto it = buffer_ids_.find(id); + if (it == buffer_ids_.end()) + return false; + int index = it->second; + buffer_ids_.erase(it); + codec_->ReleaseOutputBuffer(index, render); + return true; +} + +CodecWrapper::CodecWrapper(std::unique_ptr<MediaCodecBridge> codec) + : impl_(new CodecWrapperImpl(std::move(codec))) {} + +CodecWrapper::~CodecWrapper() { + // The codec must have already been taken. + DCHECK(!impl_->TakeCodec()); +} + +std::unique_ptr<MediaCodecBridge> CodecWrapper::TakeCodec() { + return impl_->TakeCodec(); +} + +bool CodecWrapper::HasValidCodecOutputBuffers() const { + return impl_->HasValidCodecOutputBuffers(); +} + +void CodecWrapper::DiscardCodecOutputBuffers() { + impl_->DiscardCodecOutputBuffers(); +} + +bool CodecWrapper::SupportsFlush() const { + return impl_->SupportsFlush(); +} + +bool CodecWrapper::Flush() { + return impl_->Flush(); +} + +MediaCodecStatus CodecWrapper::QueueInputBuffer( + int index, + const uint8_t* data, + size_t data_size, + base::TimeDelta presentation_time) { + return impl_->QueueInputBuffer(index, data, data_size, presentation_time); +} + +MediaCodecStatus CodecWrapper::QueueSecureInputBuffer( + int index, + const uint8_t* data, + size_t data_size, + const std::string& key_id, + const std::string& iv, + const std::vector<SubsampleEntry>& subsamples, + const EncryptionScheme& encryption_scheme, + base::TimeDelta presentation_time) { + return impl_->QueueSecureInputBuffer(index, data, data_size, key_id, iv, + subsamples, encryption_scheme, + presentation_time); +} + +void CodecWrapper::QueueEOS(int input_buffer_index) { + impl_->QueueEOS(input_buffer_index); +} + +MediaCodecStatus CodecWrapper::DequeueInputBuffer(base::TimeDelta timeout, + int* index) { + return impl_->DequeueInputBuffer(timeout, index); +} + +MediaCodecStatus CodecWrapper::DequeueOutputBuffer( + base::TimeDelta timeout, + base::TimeDelta* presentation_time, + bool* end_of_stream, + std::unique_ptr<CodecOutputBuffer>* codec_buffer) { + return impl_->DequeueOutputBuffer(timeout, presentation_time, end_of_stream, + codec_buffer); +} + +bool CodecWrapper::SetSurface(jobject surface) { + return impl_->SetSurface(surface); +} + +} // namespace media
diff --git a/media/gpu/android/codec_wrapper.h b/media/gpu/android/codec_wrapper.h new file mode 100644 index 0000000..f8a483c --- /dev/null +++ b/media/gpu/android/codec_wrapper.h
@@ -0,0 +1,118 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_GPU_ANDROID_CODEC_WRAPPER_H_ +#define MEDIA_GPU_ANDROID_CODEC_WRAPPER_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <memory> +#include <string> +#include <vector> + +#include "base/containers/flat_map.h" +#include "base/memory/ref_counted.h" +#include "base/synchronization/lock.h" +#include "media/base/android/media_codec_bridge.h" +#include "media/gpu/media_gpu_export.h" +#include "media/gpu/surface_texture_gl_owner.h" + +namespace media { +class CodecWrapperImpl; + +// A MediaCodec output buffer that can be released on any thread. +class MEDIA_GPU_EXPORT CodecOutputBuffer { + public: + // Releases the buffer without rendering it. + ~CodecOutputBuffer(); + + // Releases this buffer and renders it to the surface. + bool ReleaseToSurface(); + + // The size of the image. + gfx::Size size() const { return size_; } + + private: + // Let CodecWrapperImpl call the constructor. + friend class CodecWrapperImpl; + CodecOutputBuffer(scoped_refptr<CodecWrapperImpl> codec, + int64_t id, + gfx::Size size); + + scoped_refptr<CodecWrapperImpl> codec_; + int64_t id_; + gfx::Size size_; + DISALLOW_COPY_AND_ASSIGN(CodecOutputBuffer); +}; + +// This wraps a MediaCodecBridge and provides a pared down version of its +// interface. It also adds the following features: +// * It outputs CodecOutputBuffers from DequeueOutputBuffer() which can be +// safely rendered on any thread, and that will release their buffers on +// destruction. This lets us decode on one thread while rendering on another. +// * It maintains codec specific state like whether an error has occurred. +// +// CodecWrapper is not threadsafe, but the CodecOutputBuffers it outputs +// can be released on any thread. +class MEDIA_GPU_EXPORT CodecWrapper { + public: + // |codec| should be in the state referred to by the MediaCodec docs as + // "Flushed", i.e., freshly configured or after a Flush() call. + CodecWrapper(std::unique_ptr<MediaCodecBridge> codec); + ~CodecWrapper(); + + // Takes the backing codec and discards all outstanding codec buffers. This + // lets you tear down the codec while there are still CodecOutputBuffers + // referencing |this|. + std::unique_ptr<MediaCodecBridge> TakeCodec(); + + // Whether there are any valid CodecOutputBuffers that have not been released. + bool HasValidCodecOutputBuffers() const; + + // Releases currently dequeued codec buffers back to the codec without + // rendering. + void DiscardCodecOutputBuffers(); + + // Whether the codec supports Flush(). + bool SupportsFlush() const; + + // See MediaCodecBridge documentation for the following. + bool Flush(); + MediaCodecStatus QueueInputBuffer(int index, + const uint8_t* data, + size_t data_size, + base::TimeDelta presentation_time); + MediaCodecStatus QueueSecureInputBuffer( + int index, + const uint8_t* data, + size_t data_size, + const std::string& key_id, + const std::string& iv, + const std::vector<SubsampleEntry>& subsamples, + const EncryptionScheme& encryption_scheme, + base::TimeDelta presentation_time); + void QueueEOS(int input_buffer_index); + MediaCodecStatus DequeueInputBuffer(base::TimeDelta timeout, int* index); + + // Like MediaCodecBridge::DequeueOutputBuffer() but it outputs a + // CodecOutputBuffer instead of an index. And it's guaranteed to not return + // either of MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED or + // MEDIA_CODEC_OUTPUT_FORMAT_CHANGED. It will try to dequeue another + // buffer instead. |*codec_buffer| must be null. + MediaCodecStatus DequeueOutputBuffer( + base::TimeDelta timeout, + base::TimeDelta* presentation_time, + bool* end_of_stream, + std::unique_ptr<CodecOutputBuffer>* codec_buffer); + bool SetSurface(jobject surface); + + private: + scoped_refptr<CodecWrapperImpl> impl_; + DISALLOW_COPY_AND_ASSIGN(CodecWrapper); +}; + +} // namespace media + +#endif // MEDIA_GPU_ANDROID_CODEC_WRAPPER_H_
diff --git a/media/gpu/android/codec_wrapper_unittest.cc b/media/gpu/android/codec_wrapper_unittest.cc new file mode 100644 index 0000000..06a9bb7 --- /dev/null +++ b/media/gpu/android/codec_wrapper_unittest.cc
@@ -0,0 +1,204 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/gpu/android/codec_wrapper.h" +#include "base/bind.h" +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "base/memory/ref_counted.h" +#include "base/message_loop/message_loop.h" +#include "media/base/android/media_codec_bridge.h" +#include "media/base/android/mock_media_codec_bridge.h" +#include "media/base/encryption_scheme.h" +#include "media/base/subsample_entry.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::Invoke; +using testing::Return; +using testing::DoAll; +using testing::SetArgPointee; +using testing::NiceMock; +using testing::_; + +namespace media { + +class CodecWrapperTest : public testing::Test { + public: + CodecWrapperTest() { + auto codec = base::MakeUnique<NiceMock<MockMediaCodecBridge>>(); + codec_ = codec.get(); + wrapper_ = base::MakeUnique<CodecWrapper>(std::move(codec)); + ON_CALL(*codec_, DequeueOutputBuffer(_, _, _, _, _, _, _)) + .WillByDefault(Return(MEDIA_CODEC_OK)); + } + + ~CodecWrapperTest() override { + // ~CodecWrapper asserts that the codec was taken. + wrapper_->TakeCodec(); + } + + std::unique_ptr<CodecOutputBuffer> DequeueCodecOutputBuffer() { + std::unique_ptr<CodecOutputBuffer> codec_buffer; + wrapper_->DequeueOutputBuffer(base::TimeDelta(), nullptr, nullptr, + &codec_buffer); + return codec_buffer; + } + + NiceMock<MockMediaCodecBridge>* codec_; + std::unique_ptr<CodecWrapper> wrapper_; +}; + +TEST_F(CodecWrapperTest, TakeCodecReturnsTheCodecFirstAndNullLater) { + ASSERT_EQ(wrapper_->TakeCodec().get(), codec_); + ASSERT_EQ(wrapper_->TakeCodec(), nullptr); +} + +TEST_F(CodecWrapperTest, NoCodecOutputBufferReturnedIfDequeueFails) { + EXPECT_CALL(*codec_, DequeueOutputBuffer(_, _, _, _, _, _, _)) + .WillOnce(Return(MEDIA_CODEC_ERROR)); + auto codec_buffer = DequeueCodecOutputBuffer(); + ASSERT_EQ(codec_buffer, nullptr); +} + +TEST_F(CodecWrapperTest, InitiallyThereAreNoValidCodecOutputBuffers) { + ASSERT_FALSE(wrapper_->HasValidCodecOutputBuffers()); +} + +TEST_F(CodecWrapperTest, FlushInvalidatesCodecOutputBuffers) { + auto codec_buffer = DequeueCodecOutputBuffer(); + wrapper_->Flush(); + ASSERT_FALSE(codec_buffer->ReleaseToSurface()); +} + +TEST_F(CodecWrapperTest, TakingTheCodecInvalidatesCodecOutputBuffers) { + auto codec_buffer = DequeueCodecOutputBuffer(); + wrapper_->TakeCodec(); + ASSERT_FALSE(codec_buffer->ReleaseToSurface()); +} + +TEST_F(CodecWrapperTest, SetSurfaceInvalidatesCodecOutputBuffers) { + auto codec_buffer = DequeueCodecOutputBuffer(); + wrapper_->SetSurface(0); + ASSERT_FALSE(codec_buffer->ReleaseToSurface()); +} + +TEST_F(CodecWrapperTest, CodecOutputBuffersAreAllInvalidatedTogether) { + auto codec_buffer1 = DequeueCodecOutputBuffer(); + auto codec_buffer2 = DequeueCodecOutputBuffer(); + wrapper_->Flush(); + ASSERT_FALSE(codec_buffer1->ReleaseToSurface()); + ASSERT_FALSE(codec_buffer2->ReleaseToSurface()); + ASSERT_FALSE(wrapper_->HasValidCodecOutputBuffers()); +} + +TEST_F(CodecWrapperTest, CodecOutputBuffersAfterFlushAreValid) { + auto codec_buffer = DequeueCodecOutputBuffer(); + wrapper_->Flush(); + codec_buffer = DequeueCodecOutputBuffer(); + ASSERT_TRUE(codec_buffer->ReleaseToSurface()); +} + +TEST_F(CodecWrapperTest, CodecOutputBufferReleaseUsesCorrectIndex) { + // The second arg is the buffer index pointer. + EXPECT_CALL(*codec_, DequeueOutputBuffer(_, _, _, _, _, _, _)) + .WillOnce(DoAll(SetArgPointee<1>(42), Return(MEDIA_CODEC_OK))); + auto codec_buffer = DequeueCodecOutputBuffer(); + EXPECT_CALL(*codec_, ReleaseOutputBuffer(42, true)); + codec_buffer->ReleaseToSurface(); +} + +TEST_F(CodecWrapperTest, CodecOutputBuffersAreInvalidatedByRelease) { + auto codec_buffer = DequeueCodecOutputBuffer(); + codec_buffer->ReleaseToSurface(); + ASSERT_FALSE(codec_buffer->ReleaseToSurface()); +} + +TEST_F(CodecWrapperTest, CodecOutputBuffersReleaseOnDestruction) { + auto codec_buffer = DequeueCodecOutputBuffer(); + EXPECT_CALL(*codec_, ReleaseOutputBuffer(_, false)); + codec_buffer = nullptr; +} + +TEST_F(CodecWrapperTest, CodecOutputBuffersDoNotReleaseIfAlreadyReleased) { + auto codec_buffer = DequeueCodecOutputBuffer(); + codec_buffer->ReleaseToSurface(); + EXPECT_CALL(*codec_, ReleaseOutputBuffer(_, _)).Times(0); + codec_buffer = nullptr; +} + +TEST_F(CodecWrapperTest, ReleasingCodecOutputBuffersAfterTheCodecIsSafe) { + auto codec_buffer = DequeueCodecOutputBuffer(); + wrapper_->TakeCodec(); + codec_buffer->ReleaseToSurface(); +} + +TEST_F(CodecWrapperTest, DeletingCodecOutputBuffersAfterTheCodecIsSafe) { + auto codec_buffer = DequeueCodecOutputBuffer(); + wrapper_->TakeCodec(); + // This test ensures the destructor doesn't crash. + codec_buffer = nullptr; +} + +TEST_F(CodecWrapperTest, CodecOutputBufferReleaseDoesNotInvalidateOthers) { + auto codec_buffer1 = DequeueCodecOutputBuffer(); + auto codec_buffer2 = DequeueCodecOutputBuffer(); + codec_buffer1->ReleaseToSurface(); + ASSERT_TRUE(codec_buffer2->ReleaseToSurface()); +} + +TEST_F(CodecWrapperTest, FormatChangedStatusIsSwallowed) { + EXPECT_CALL(*codec_, DequeueOutputBuffer(_, _, _, _, _, _, _)) + .WillOnce(Return(MEDIA_CODEC_OUTPUT_FORMAT_CHANGED)) + .WillOnce(Return(MEDIA_CODEC_TRY_AGAIN_LATER)); + std::unique_ptr<CodecOutputBuffer> codec_buffer; + auto status = wrapper_->DequeueOutputBuffer(base::TimeDelta(), nullptr, + nullptr, &codec_buffer); + ASSERT_EQ(status, MEDIA_CODEC_TRY_AGAIN_LATER); +} + +TEST_F(CodecWrapperTest, BuffersChangedStatusIsSwallowed) { + EXPECT_CALL(*codec_, DequeueOutputBuffer(_, _, _, _, _, _, _)) + .WillOnce(Return(MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED)) + .WillOnce(Return(MEDIA_CODEC_TRY_AGAIN_LATER)); + std::unique_ptr<CodecOutputBuffer> codec_buffer; + auto status = wrapper_->DequeueOutputBuffer(base::TimeDelta(), nullptr, + nullptr, &codec_buffer); + ASSERT_EQ(status, MEDIA_CODEC_TRY_AGAIN_LATER); +} + +TEST_F(CodecWrapperTest, MultipleFormatChangedStatusesIsAnError) { + EXPECT_CALL(*codec_, DequeueOutputBuffer(_, _, _, _, _, _, _)) + .WillRepeatedly(Return(MEDIA_CODEC_OUTPUT_FORMAT_CHANGED)); + std::unique_ptr<CodecOutputBuffer> codec_buffer; + auto status = wrapper_->DequeueOutputBuffer(base::TimeDelta(), nullptr, + nullptr, &codec_buffer); + ASSERT_EQ(status, MEDIA_CODEC_ERROR); +} + +TEST_F(CodecWrapperTest, CodecOutputBuffersHaveTheCorrectSize) { + EXPECT_CALL(*codec_, DequeueOutputBuffer(_, _, _, _, _, _, _)) + .WillOnce(Return(MEDIA_CODEC_OUTPUT_FORMAT_CHANGED)) + .WillOnce(Return(MEDIA_CODEC_OK)); + EXPECT_CALL(*codec_, GetOutputSize(_)) + .WillOnce( + DoAll(SetArgPointee<0>(gfx::Size(42, 42)), Return(MEDIA_CODEC_OK))); + auto codec_buffer = DequeueCodecOutputBuffer(); + ASSERT_EQ(codec_buffer->size(), gfx::Size(42, 42)); +} + +#if DCHECK_IS_ON() +TEST_F(CodecWrapperTest, CallsDcheckAfterTakingTheCodec) { + wrapper_->TakeCodec(); + ASSERT_DEATH(wrapper_->Flush(), ""); +} + +TEST_F(CodecWrapperTest, CallsDcheckAfterAnError) { + EXPECT_CALL(*codec_, Flush()).WillOnce(Return(MEDIA_CODEC_ERROR)); + wrapper_->Flush(); + ASSERT_DEATH(wrapper_->SetSurface(0), ""); +} +#endif + +} // namespace media
diff --git a/media/test/BUILD.gn b/media/test/BUILD.gn index 5012118..c415cfe0 100644 --- a/media/test/BUILD.gn +++ b/media/test/BUILD.gn
@@ -166,4 +166,6 @@ # This is done to suppress tons of log messages generated by gmock asserts. "close_fd_mask=1", ] + + seed_corpus = "media/test/data/" }
diff --git a/mojo/edk/system/BUILD.gn b/mojo/edk/system/BUILD.gn index a68cd44..8dd8cf8 100644 --- a/mojo/edk/system/BUILD.gn +++ b/mojo/edk/system/BUILD.gn
@@ -42,8 +42,6 @@ "handle_table.h", "mapping_table.cc", "mapping_table.h", - "message_for_transit.cc", - "message_for_transit.h", "message_pipe_dispatcher.cc", "message_pipe_dispatcher.h", "node_channel.cc", @@ -53,12 +51,12 @@ "options_validation.h", "platform_handle_dispatcher.cc", "platform_handle_dispatcher.h", - "ports_message.cc", - "ports_message.h", "request_context.cc", "request_context.h", "shared_buffer_dispatcher.cc", "shared_buffer_dispatcher.h", + "user_message_impl.cc", + "user_message_impl.h", "watch.cc", "watch.h", "watcher_dispatcher.cc",
diff --git a/mojo/edk/system/core.cc b/mojo/edk/system/core.cc index 5561baa5..dc61172 100644 --- a/mojo/edk/system/core.cc +++ b/mojo/edk/system/core.cc
@@ -26,13 +26,14 @@ #include "mojo/edk/system/data_pipe_consumer_dispatcher.h" #include "mojo/edk/system/data_pipe_producer_dispatcher.h" #include "mojo/edk/system/handle_signals_state.h" -#include "mojo/edk/system/message_for_transit.h" #include "mojo/edk/system/message_pipe_dispatcher.h" #include "mojo/edk/system/platform_handle_dispatcher.h" +#include "mojo/edk/system/ports/event.h" #include "mojo/edk/system/ports/name.h" #include "mojo/edk/system/ports/node.h" #include "mojo/edk/system/request_context.h" #include "mojo/edk/system/shared_buffer_dispatcher.h" +#include "mojo/edk/system/user_message_impl.h" #include "mojo/edk/system/watcher_dispatcher.h" namespace mojo { @@ -435,17 +436,18 @@ const MojoHandle* handles, uint32_t num_handles, MojoAllocMessageFlags flags, - MojoMessageHandle* message) { - if (!message) + MojoMessageHandle* message_handle) { + if (!message_handle) return MOJO_RESULT_INVALID_ARGUMENT; if (num_handles == 0) { // Fast path: no handles. - std::unique_ptr<MessageForTransit> msg; - MojoResult rv = MessageForTransit::Create(&msg, num_bytes, nullptr, 0); + std::unique_ptr<ports::UserMessageEvent> message; + MojoResult rv = UserMessageImpl::CreateEventForNewSerializedMessage( + num_bytes, nullptr, 0, &message); if (rv != MOJO_RESULT_OK) return rv; - *message = reinterpret_cast<MojoMessageHandle>(msg.release()); + *message_handle = reinterpret_cast<MojoMessageHandle>(message.release()); return MOJO_RESULT_OK; } @@ -470,15 +472,15 @@ } DCHECK_EQ(num_handles, dispatchers.size()); - std::unique_ptr<MessageForTransit> msg; - MojoResult rv = MessageForTransit::Create( - &msg, num_bytes, dispatchers.data(), num_handles); + std::unique_ptr<ports::UserMessageEvent> message; + MojoResult rv = UserMessageImpl::CreateEventForNewSerializedMessage( + num_bytes, dispatchers.data(), num_handles, &message); { base::AutoLock lock(handles_lock_); if (rv == MOJO_RESULT_OK) { handles_.CompleteTransitAndClose(dispatchers); - *message = reinterpret_cast<MojoMessageHandle>(msg.release()); + *message_handle = reinterpret_cast<MojoMessageHandle>(message.release()); } else { handles_.CancelTransit(dispatchers); } @@ -487,22 +489,26 @@ return rv; } -MojoResult Core::FreeMessage(MojoMessageHandle message) { - if (!message) +MojoResult Core::FreeMessage(MojoMessageHandle message_handle) { + if (!message_handle) return MOJO_RESULT_INVALID_ARGUMENT; RequestContext request_context; - delete reinterpret_cast<MessageForTransit*>(message); - + delete reinterpret_cast<ports::UserMessageEvent*>(message_handle); return MOJO_RESULT_OK; } -MojoResult Core::GetMessageBuffer(MojoMessageHandle message, void** buffer) { - if (!message) +MojoResult Core::GetMessageBuffer(MojoMessageHandle message_handle, + void** buffer) { + if (!message_handle) return MOJO_RESULT_INVALID_ARGUMENT; - *buffer = reinterpret_cast<MessageForTransit*>(message)->mutable_bytes(); + auto* message = reinterpret_cast<ports::UserMessageEvent*>(message_handle) + ->GetMessage<UserMessageImpl>(); + if (!message->IsSerialized()) + return MOJO_RESULT_NOT_FOUND; + *buffer = message->user_payload(); return MOJO_RESULT_OK; } @@ -525,8 +531,8 @@ ports::PortRef port0, port1; GetNodeController()->node()->CreatePortPair(&port0, &port1); - CHECK(message_pipe_handle0); - CHECK(message_pipe_handle1); + DCHECK(message_pipe_handle0); + DCHECK(message_pipe_handle1); uint64_t pipe_id = base::RandUint64(); @@ -575,16 +581,15 @@ } MojoResult Core::WriteMessageNew(MojoHandle message_pipe_handle, - MojoMessageHandle message, + MojoMessageHandle message_handle, MojoWriteMessageFlags flags) { RequestContext request_context; - std::unique_ptr<MessageForTransit> message_for_transit( - reinterpret_cast<MessageForTransit*>(message)); + auto message = base::WrapUnique( + reinterpret_cast<ports::UserMessageEvent*>(message_handle)); auto dispatcher = GetDispatcher(message_pipe_handle); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; - - return dispatcher->WriteMessage(std::move(message_for_transit), flags); + return dispatcher->WriteMessage(std::move(message), flags); } MojoResult Core::ReadMessage(MojoHandle message_pipe_handle, @@ -593,44 +598,55 @@ MojoHandle* handles, uint32_t* num_handles, MojoReadMessageFlags flags) { - CHECK((!num_handles || !*num_handles || handles) && - (!num_bytes || !*num_bytes || bytes)); + DCHECK((!num_handles || !*num_handles || handles) && + (!num_bytes || !*num_bytes || bytes)); RequestContext request_context; auto dispatcher = GetDispatcher(message_pipe_handle); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; - std::unique_ptr<MessageForTransit> message; + std::unique_ptr<ports::UserMessageEvent> message_event; MojoResult rv = - dispatcher->ReadMessage(&message, num_bytes, handles, num_handles, flags, - false /* ignore_num_bytes */); + dispatcher->ReadMessage(&message_event, num_bytes, handles, num_handles, + flags, false /* ignore_num_bytes */); if (rv != MOJO_RESULT_OK) return rv; - if (message && message->num_bytes()) - memcpy(bytes, message->bytes(), message->num_bytes()); + // Some tests use fake message pipe dispatchers which return null events. + // + // TODO(rockot): Fix the tests, because this is weird. + if (!message_event) + return MOJO_RESULT_OK; + auto* message = message_event->GetMessage<UserMessageImpl>(); + if (!message->IsSerialized()) + return MOJO_RESULT_UNKNOWN; // Maybe we need a better result code. + + if (message->user_payload_size()) + memcpy(bytes, message->user_payload(), message->user_payload_size()); return MOJO_RESULT_OK; } MojoResult Core::ReadMessageNew(MojoHandle message_pipe_handle, - MojoMessageHandle* message, + MojoMessageHandle* message_handle, uint32_t* num_bytes, MojoHandle* handles, uint32_t* num_handles, MojoReadMessageFlags flags) { - CHECK(message); - CHECK(!num_handles || !*num_handles || handles); + DCHECK(message_handle); + DCHECK(!num_handles || !*num_handles || handles); RequestContext request_context; auto dispatcher = GetDispatcher(message_pipe_handle); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; - std::unique_ptr<MessageForTransit> msg; + std::unique_ptr<ports::UserMessageEvent> message_event; MojoResult rv = - dispatcher->ReadMessage(&msg, num_bytes, handles, num_handles, flags, - true /* ignore_num_bytes */); + dispatcher->ReadMessage(&message_event, num_bytes, handles, num_handles, + flags, true /* ignore_num_bytes */); if (rv != MOJO_RESULT_OK) return rv; - *message = reinterpret_cast<MojoMessageHandle>(msg.release()); + + *message_handle = + reinterpret_cast<MojoMessageHandle>(message_event.release()); return MOJO_RESULT_OK; } @@ -669,15 +685,16 @@ return MOJO_RESULT_OK; } -MojoResult Core::NotifyBadMessage(MojoMessageHandle message, +MojoResult Core::NotifyBadMessage(MojoMessageHandle message_handle, const char* error, size_t error_num_bytes) { - if (!message) + if (!message_handle) return MOJO_RESULT_INVALID_ARGUMENT; - const PortsMessage& ports_message = - reinterpret_cast<MessageForTransit*>(message)->ports_message(); - if (ports_message.source_node() == ports::kInvalidNodeName) { + auto* message_event = + reinterpret_cast<ports::UserMessageEvent*>(message_handle); + auto* message = message_event->GetMessage<UserMessageImpl>(); + if (message->source_node() == ports::kInvalidNodeName) { DVLOG(1) << "Received invalid message from unknown node."; if (!default_process_error_callback_.is_null()) default_process_error_callback_.Run(std::string(error, error_num_bytes)); @@ -685,7 +702,7 @@ } GetNodeController()->NotifyBadMessageFrom( - ports_message.source_node(), std::string(error, error_num_bytes)); + message->source_node(), std::string(error, error_num_bytes)); return MOJO_RESULT_OK; } @@ -991,12 +1008,12 @@ static_cast<SharedBufferDispatcher*>(dispatcher.get()); scoped_refptr<PlatformSharedBuffer> platform_shared_buffer = shm_dispatcher->PassPlatformSharedBuffer(); - CHECK(platform_shared_buffer); + DCHECK(platform_shared_buffer); - CHECK(size); + DCHECK(size); *size = platform_shared_buffer->GetNumBytes(); - CHECK(flags); + DCHECK(flags); *flags = MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_NONE; if (platform_shared_buffer->IsReadOnly()) *flags |= MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_READ_ONLY;
diff --git a/mojo/edk/system/core.h b/mojo/edk/system/core.h index c2d0aa71..18c1167 100644 --- a/mojo/edk/system/core.h +++ b/mojo/edk/system/core.h
@@ -175,9 +175,9 @@ const MojoHandle* handles, uint32_t num_handles, MojoAllocMessageFlags flags, - MojoMessageHandle* message); - MojoResult FreeMessage(MojoMessageHandle message); - MojoResult GetMessageBuffer(MojoMessageHandle message, void** buffer); + MojoMessageHandle* message_handle); + MojoResult FreeMessage(MojoMessageHandle message_handle); + MojoResult GetMessageBuffer(MojoMessageHandle message_handle, void** buffer); MojoResult GetProperty(MojoPropertyType type, void* value); // These methods correspond to the API functions defined in @@ -193,7 +193,7 @@ uint32_t num_handles, MojoWriteMessageFlags flags); MojoResult WriteMessageNew(MojoHandle message_pipe_handle, - MojoMessageHandle message, + MojoMessageHandle message_handle, MojoWriteMessageFlags flags); MojoResult ReadMessage(MojoHandle message_pipe_handle, void* bytes, @@ -202,13 +202,13 @@ uint32_t* num_handles, MojoReadMessageFlags flags); MojoResult ReadMessageNew(MojoHandle message_pipe_handle, - MojoMessageHandle* message, + MojoMessageHandle* message_handle, uint32_t* num_bytes, MojoHandle* handles, uint32_t* num_handles, MojoReadMessageFlags flags); MojoResult FuseMessagePipes(MojoHandle handle0, MojoHandle handle1); - MojoResult NotifyBadMessage(MojoMessageHandle message, + MojoResult NotifyBadMessage(MojoMessageHandle message_handle, const char* error, size_t error_num_bytes);
diff --git a/mojo/edk/system/core_test_base.cc b/mojo/edk/system/core_test_base.cc index 7751612e..e518f3d 100644 --- a/mojo/edk/system/core_test_base.cc +++ b/mojo/edk/system/core_test_base.cc
@@ -16,7 +16,7 @@ #include "mojo/edk/system/configuration.h" #include "mojo/edk/system/core.h" #include "mojo/edk/system/dispatcher.h" -#include "mojo/edk/system/message_for_transit.h" +#include "mojo/edk/system/user_message_impl.h" namespace mojo { namespace edk { @@ -42,11 +42,12 @@ } MojoResult WriteMessage( - std::unique_ptr<MessageForTransit> message, + std::unique_ptr<ports::UserMessageEvent> message_event, MojoWriteMessageFlags /*flags*/) override { info_->IncrementWriteMessageCallCount(); - if (message->num_bytes() > GetConfiguration().max_message_num_bytes) + auto* message = message_event->GetMessage<UserMessageImpl>(); + if (message->user_payload_size() > GetConfiguration().max_message_num_bytes) return MOJO_RESULT_RESOURCE_EXHAUSTED; if (message->num_handles()) @@ -55,12 +56,13 @@ return MOJO_RESULT_OK; } - MojoResult ReadMessage(std::unique_ptr<MessageForTransit>* message, - uint32_t* num_bytes, - MojoHandle* handle, - uint32_t* num_handles, - MojoReadMessageFlags /*flags*/, - bool ignore_num_bytes) override { + MojoResult ReadMessage( + std::unique_ptr<ports::UserMessageEvent>* message_event, + uint32_t* num_bytes, + MojoHandle* handle, + uint32_t* num_handles, + MojoReadMessageFlags /*flags*/, + bool ignore_num_bytes) override { info_->IncrementReadMessageCallCount(); if (num_handles)
diff --git a/mojo/edk/system/data_pipe_consumer_dispatcher.cc b/mojo/edk/system/data_pipe_consumer_dispatcher.cc index 7e4f084c..a0f6119 100644 --- a/mojo/edk/system/data_pipe_consumer_dispatcher.cc +++ b/mojo/edk/system/data_pipe_consumer_dispatcher.cc
@@ -20,8 +20,8 @@ #include "mojo/edk/system/core.h" #include "mojo/edk/system/data_pipe_control_message.h" #include "mojo/edk/system/node_controller.h" -#include "mojo/edk/system/ports_message.h" #include "mojo/edk/system/request_context.h" +#include "mojo/edk/system/user_message_impl.h" #include "mojo/public/c/system/data_pipe.h" namespace mojo { @@ -527,21 +527,21 @@ << " [control_port=" << control_port_.name() << "]"; peer_closed_ = true; } else if (rv == ports::OK && port_status.has_messages && !in_transit_) { - ports::ScopedMessage message; + std::unique_ptr<ports::UserMessageEvent> message_event; do { - int rv = node_controller_->node()->GetMessage( - control_port_, &message, nullptr); + int rv = node_controller_->node()->GetMessage(control_port_, + &message_event, nullptr); if (rv != ports::OK) peer_closed_ = true; - if (message) { - if (message->num_payload_bytes() < sizeof(DataPipeControlMessage)) { + if (message_event) { + auto* message = message_event->GetMessage<UserMessageImpl>(); + if (message->user_payload_size() < sizeof(DataPipeControlMessage)) { peer_closed_ = true; break; } const DataPipeControlMessage* m = - static_cast<const DataPipeControlMessage*>( - message->payload_bytes()); + static_cast<const DataPipeControlMessage*>(message->user_payload()); if (m->command != DataPipeCommand::DATA_WAS_WRITTEN) { DLOG(ERROR) << "Unexpected control message from producer."; @@ -562,7 +562,7 @@ bytes_available_ += m->num_bytes; } - } while (message); + } while (message_event); } bool has_new_data = bytes_available_ != previous_bytes_available;
diff --git a/mojo/edk/system/data_pipe_control_message.cc b/mojo/edk/system/data_pipe_control_message.cc index 23873b82..22a32f8 100644 --- a/mojo/edk/system/data_pipe_control_message.cc +++ b/mojo/edk/system/data_pipe_control_message.cc
@@ -6,7 +6,8 @@ #include "mojo/edk/embedder/platform_handle_vector.h" #include "mojo/edk/system/node_controller.h" -#include "mojo/edk/system/ports_message.h" +#include "mojo/edk/system/ports/event.h" +#include "mojo/edk/system/user_message_impl.h" namespace mojo { namespace edk { @@ -15,16 +16,18 @@ const ports::PortRef& port, DataPipeCommand command, uint32_t num_bytes) { - std::unique_ptr<PortsMessage> message = - PortsMessage::NewUserMessage(sizeof(DataPipeControlMessage), 0, 0); - CHECK(message); + std::unique_ptr<ports::UserMessageEvent> event; + MojoResult result = UserMessageImpl::CreateEventForNewSerializedMessage( + sizeof(DataPipeControlMessage), nullptr, 0, &event); + DCHECK_EQ(MOJO_RESULT_OK, result); + DCHECK(event); - DataPipeControlMessage* data = - static_cast<DataPipeControlMessage*>(message->mutable_payload_bytes()); + DataPipeControlMessage* data = static_cast<DataPipeControlMessage*>( + event->GetMessage<UserMessageImpl>()->user_payload()); data->command = command; data->num_bytes = num_bytes; - int rv = node_controller->SendMessage(port, std::move(message)); + int rv = node_controller->SendUserMessage(port, std::move(event)); if (rv != ports::OK && rv != ports::ERROR_PORT_PEER_CLOSED) { DLOG(ERROR) << "Unexpected failure sending data pipe control message: " << rv;
diff --git a/mojo/edk/system/data_pipe_producer_dispatcher.cc b/mojo/edk/system/data_pipe_producer_dispatcher.cc index 126f56f..b40b621 100644 --- a/mojo/edk/system/data_pipe_producer_dispatcher.cc +++ b/mojo/edk/system/data_pipe_producer_dispatcher.cc
@@ -19,8 +19,8 @@ #include "mojo/edk/system/core.h" #include "mojo/edk/system/data_pipe_control_message.h" #include "mojo/edk/system/node_controller.h" -#include "mojo/edk/system/ports_message.h" #include "mojo/edk/system/request_context.h" +#include "mojo/edk/system/user_message_impl.h" #include "mojo/public/c/system/data_pipe.h" namespace mojo { @@ -476,21 +476,21 @@ << " [control_port=" << control_port_.name() << "]"; peer_closed_ = true; } else if (rv == ports::OK && port_status.has_messages && !in_transit_) { - ports::ScopedMessage message; + std::unique_ptr<ports::UserMessageEvent> message_event; do { - int rv = node_controller_->node()->GetMessage( - control_port_, &message, nullptr); + int rv = node_controller_->node()->GetMessage(control_port_, + &message_event, nullptr); if (rv != ports::OK) peer_closed_ = true; - if (message) { - if (message->num_payload_bytes() < sizeof(DataPipeControlMessage)) { + if (message_event) { + auto* message = message_event->GetMessage<UserMessageImpl>(); + if (message->user_payload_size() < sizeof(DataPipeControlMessage)) { peer_closed_ = true; break; } const DataPipeControlMessage* m = - static_cast<const DataPipeControlMessage*>( - message->payload_bytes()); + static_cast<const DataPipeControlMessage*>(message->user_payload()); if (m->command != DataPipeCommand::DATA_WAS_READ) { DLOG(ERROR) << "Unexpected message from consumer."; @@ -510,7 +510,7 @@ available_capacity_ += m->num_bytes; } - } while (message); + } while (message_event); } if (peer_closed_ != was_peer_closed ||
diff --git a/mojo/edk/system/dispatcher.cc b/mojo/edk/system/dispatcher.cc index 7cdbe910..c144a00 100644 --- a/mojo/edk/system/dispatcher.cc +++ b/mojo/edk/system/dispatcher.cc
@@ -10,6 +10,7 @@ #include "mojo/edk/system/data_pipe_producer_dispatcher.h" #include "mojo/edk/system/message_pipe_dispatcher.h" #include "mojo/edk/system/platform_handle_dispatcher.h" +#include "mojo/edk/system/ports/event.h" #include "mojo/edk/system/shared_buffer_dispatcher.h" namespace mojo { @@ -39,17 +40,19 @@ return MOJO_RESULT_INVALID_ARGUMENT; } -MojoResult Dispatcher::WriteMessage(std::unique_ptr<MessageForTransit> message, - MojoWriteMessageFlags flags) { +MojoResult Dispatcher::WriteMessage( + std::unique_ptr<ports::UserMessageEvent> message, + MojoWriteMessageFlags flags) { return MOJO_RESULT_INVALID_ARGUMENT; } -MojoResult Dispatcher::ReadMessage(std::unique_ptr<MessageForTransit>* message, - uint32_t* num_bytes, - MojoHandle* handles, - uint32_t* num_handles, - MojoReadMessageFlags flags, - bool read_any_size) { +MojoResult Dispatcher::ReadMessage( + std::unique_ptr<ports::UserMessageEvent>* message, + uint32_t* num_bytes, + MojoHandle* handles, + uint32_t* num_handles, + MojoReadMessageFlags flags, + bool read_any_size) { return MOJO_RESULT_INVALID_ARGUMENT; }
diff --git a/mojo/edk/system/dispatcher.h b/mojo/edk/system/dispatcher.h index db1f1f1..0863da5 100644 --- a/mojo/edk/system/dispatcher.h +++ b/mojo/edk/system/dispatcher.h
@@ -29,8 +29,11 @@ namespace mojo { namespace edk { +namespace ports { +class UserMessageEvent; +} + class Dispatcher; -class MessageForTransit; using DispatcherVector = std::vector<scoped_refptr<Dispatcher>>; @@ -78,15 +81,17 @@ ///////////// Message pipe API ///////////// - virtual MojoResult WriteMessage(std::unique_ptr<MessageForTransit> message, - MojoWriteMessageFlags flags); + virtual MojoResult WriteMessage( + std::unique_ptr<ports::UserMessageEvent> message, + MojoWriteMessageFlags flags); - virtual MojoResult ReadMessage(std::unique_ptr<MessageForTransit>* message, - uint32_t* num_bytes, - MojoHandle* handles, - uint32_t* num_handles, - MojoReadMessageFlags flags, - bool read_any_size); + virtual MojoResult ReadMessage( + std::unique_ptr<ports::UserMessageEvent>* message, + uint32_t* num_bytes, + MojoHandle* handles, + uint32_t* num_handles, + MojoReadMessageFlags flags, + bool read_any_size); ///////////// Shared buffer API /////////////
diff --git a/mojo/edk/system/message_for_transit.cc b/mojo/edk/system/message_for_transit.cc deleted file mode 100644 index 26658e16..0000000 --- a/mojo/edk/system/message_for_transit.cc +++ /dev/null
@@ -1,136 +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 "mojo/edk/system/message_for_transit.h" - -#include <vector> - -#include "mojo/edk/embedder/platform_handle_vector.h" - -namespace mojo { -namespace edk { - -namespace { - -static_assert(sizeof(MessageForTransit::MessageHeader) % 8 == 0, - "Invalid MessageHeader size."); -static_assert(sizeof(MessageForTransit::DispatcherHeader) % 8 == 0, - "Invalid DispatcherHeader size."); - -} // namespace - -MessageForTransit::~MessageForTransit() {} - -// static -MojoResult MessageForTransit::Create( - std::unique_ptr<MessageForTransit>* message, - uint32_t num_bytes, - const Dispatcher::DispatcherInTransit* dispatchers, - uint32_t num_dispatchers) { - // A structure for retaining information about every Dispatcher that will be - // sent with this message. - struct DispatcherInfo { - uint32_t num_bytes; - uint32_t num_ports; - uint32_t num_handles; - }; - - // This is only the base header size. It will grow as we accumulate the - // size of serialized state for each dispatcher. - size_t header_size = sizeof(MessageHeader) + - num_dispatchers * sizeof(DispatcherHeader); - size_t num_ports = 0; - size_t num_handles = 0; - - std::vector<DispatcherInfo> dispatcher_info(num_dispatchers); - for (size_t i = 0; i < num_dispatchers; ++i) { - Dispatcher* d = dispatchers[i].dispatcher.get(); - d->StartSerialize(&dispatcher_info[i].num_bytes, - &dispatcher_info[i].num_ports, - &dispatcher_info[i].num_handles); - header_size += dispatcher_info[i].num_bytes; - num_ports += dispatcher_info[i].num_ports; - num_handles += dispatcher_info[i].num_handles; - } - - // We now have enough information to fully allocate the message storage. - std::unique_ptr<PortsMessage> msg = PortsMessage::NewUserMessage( - header_size + num_bytes, num_ports, num_handles); - if (!msg) - return MOJO_RESULT_RESOURCE_EXHAUSTED; - - // Populate the message header with information about serialized dispatchers. - // - // The front of the message is always a MessageHeader followed by a - // DispatcherHeader for each dispatcher to be sent. - MessageHeader* header = - static_cast<MessageHeader*>(msg->mutable_payload_bytes()); - DispatcherHeader* dispatcher_headers = - reinterpret_cast<DispatcherHeader*>(header + 1); - - // Serialized dispatcher state immediately follows the series of - // DispatcherHeaders. - char* dispatcher_data = - reinterpret_cast<char*>(dispatcher_headers + num_dispatchers); - - header->num_dispatchers = num_dispatchers; - - // |header_size| is the total number of bytes preceding the message payload, - // including all dispatcher headers and serialized dispatcher state. - DCHECK_LE(header_size, std::numeric_limits<uint32_t>::max()); - header->header_size = static_cast<uint32_t>(header_size); - - if (num_dispatchers > 0) { - ScopedPlatformHandleVectorPtr handles( - new PlatformHandleVector(num_handles)); - size_t port_index = 0; - size_t handle_index = 0; - bool fail = false; - for (size_t i = 0; i < num_dispatchers; ++i) { - Dispatcher* d = dispatchers[i].dispatcher.get(); - DispatcherHeader* dh = &dispatcher_headers[i]; - const DispatcherInfo& info = dispatcher_info[i]; - - // Fill in the header for this dispatcher. - dh->type = static_cast<int32_t>(d->GetType()); - dh->num_bytes = info.num_bytes; - dh->num_ports = info.num_ports; - dh->num_platform_handles = info.num_handles; - - // Fill in serialized state, ports, and platform handles. We'll cancel - // the send if the dispatcher implementation rejects for some reason. - if (!d->EndSerialize(static_cast<void*>(dispatcher_data), - msg->mutable_ports() + port_index, - handles->data() + handle_index)) { - fail = true; - break; - } - - dispatcher_data += info.num_bytes; - port_index += info.num_ports; - handle_index += info.num_handles; - } - - if (fail) { - // Release any platform handles we've accumulated. Their dispatchers - // retain ownership when message creation fails, so these are not actually - // leaking. - handles->clear(); - return MOJO_RESULT_INVALID_ARGUMENT; - } - - // Take ownership of all the handles and move them into message storage. - msg->SetHandles(std::move(handles)); - } - - message->reset(new MessageForTransit(std::move(msg))); - return MOJO_RESULT_OK; -} - -MessageForTransit::MessageForTransit(std::unique_ptr<PortsMessage> message) - : message_(std::move(message)) { -} - -} // namespace edk -} // namespace mojo
diff --git a/mojo/edk/system/message_for_transit.h b/mojo/edk/system/message_for_transit.h deleted file mode 100644 index 6103a771..0000000 --- a/mojo/edk/system/message_for_transit.h +++ /dev/null
@@ -1,115 +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 MOJO_EDK_SYSTEM_MESSAGE_FOR_TRANSIT_H_ -#define MOJO_EDK_SYSTEM_MESSAGE_FOR_TRANSIT_H_ - -#include <stdint.h> - -#include <memory> - -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "mojo/edk/system/dispatcher.h" -#include "mojo/edk/system/ports_message.h" -#include "mojo/edk/system/system_impl_export.h" - -namespace mojo { -namespace edk { - -// MessageForTransit holds onto a PortsMessage which may be sent via -// |MojoWriteMessage()| or which may have been received on a pipe endpoint. -// Instances of this class are exposed to Mojo system API consumers via the -// opaque pointers used with |MojoCreateMessage()|, |MojoDestroyMessage()|, -// |MojoWriteMessageNew()|, and |MojoReadMessageNew()|. -class MOJO_SYSTEM_IMPL_EXPORT MessageForTransit { - public: -#pragma pack(push, 1) - // Header attached to every message. - struct MessageHeader { - // The number of serialized dispatchers included in this header. - uint32_t num_dispatchers; - - // Total size of the header, including serialized dispatcher data. - uint32_t header_size; - }; - - // Header for each dispatcher in a message, immediately following the message - // header. - struct DispatcherHeader { - // The type of the dispatcher, correpsonding to the Dispatcher::Type enum. - int32_t type; - - // The size of the serialized dispatcher, not including this header. - uint32_t num_bytes; - - // The number of ports needed to deserialize this dispatcher. - uint32_t num_ports; - - // The number of platform handles needed to deserialize this dispatcher. - uint32_t num_platform_handles; - }; -#pragma pack(pop) - - ~MessageForTransit(); - - // A static constructor for building outbound messages. - static MojoResult Create( - std::unique_ptr<MessageForTransit>* message, - uint32_t num_bytes, - const Dispatcher::DispatcherInTransit* dispatchers, - uint32_t num_dispatchers); - - // A static constructor for wrapping inbound messages. - static std::unique_ptr<MessageForTransit> WrapPortsMessage( - std::unique_ptr<PortsMessage> message) { - return base::WrapUnique(new MessageForTransit(std::move(message))); - } - - const void* bytes() const { - DCHECK(message_); - return static_cast<const void*>( - static_cast<const char*>(message_->payload_bytes()) + - header()->header_size); - } - - void* mutable_bytes() { - DCHECK(message_); - return static_cast<void*>( - static_cast<char*>(message_->mutable_payload_bytes()) + - header()->header_size); - } - - size_t num_bytes() const { - size_t header_size = header()->header_size; - DCHECK_GE(message_->num_payload_bytes(), header_size); - return message_->num_payload_bytes() - header_size; - } - - size_t num_handles() const { return header()->num_dispatchers; } - - const PortsMessage& ports_message() const { return *message_; } - - std::unique_ptr<PortsMessage> TakePortsMessage() { - return std::move(message_); - } - - private: - explicit MessageForTransit(std::unique_ptr<PortsMessage> message); - - const MessageForTransit::MessageHeader* header() const { - DCHECK(message_); - return static_cast<const MessageForTransit::MessageHeader*>( - message_->payload_bytes()); - } - - std::unique_ptr<PortsMessage> message_; - - DISALLOW_COPY_AND_ASSIGN(MessageForTransit); -}; - -} // namespace edk -} // namespace mojo - -#endif // MOJO_EDK_SYSTEM_MESSAGE_FOR_TRANSIT_H_
diff --git a/mojo/edk/system/message_pipe_dispatcher.cc b/mojo/edk/system/message_pipe_dispatcher.cc index 1db56c0..82d5f0f 100644 --- a/mojo/edk/system/message_pipe_dispatcher.cc +++ b/mojo/edk/system/message_pipe_dispatcher.cc
@@ -12,20 +12,17 @@ #include "base/memory/ref_counted.h" #include "mojo/edk/embedder/embedder_internal.h" #include "mojo/edk/system/core.h" -#include "mojo/edk/system/message_for_transit.h" #include "mojo/edk/system/node_controller.h" +#include "mojo/edk/system/ports/event.h" #include "mojo/edk/system/ports/message_filter.h" -#include "mojo/edk/system/ports_message.h" #include "mojo/edk/system/request_context.h" +#include "mojo/edk/system/user_message_impl.h" namespace mojo { namespace edk { namespace { -using DispatcherHeader = MessageForTransit::DispatcherHeader; -using MessageHeader = MessageForTransit::MessageHeader; - #pragma pack(push, 1) struct SerializedState { @@ -60,78 +57,6 @@ DISALLOW_COPY_AND_ASSIGN(PortObserverThunk); }; -// A MessageFilter used by ReadMessage to determine whether a message should -// actually be consumed yet. -class ReadMessageFilter : public ports::MessageFilter { - public: - // Creates a new ReadMessageFilter which captures and potentially modifies - // various (unowned) local state within MessagePipeDispatcher::ReadMessage. - ReadMessageFilter(bool read_any_size, - bool may_discard, - uint32_t* num_bytes, - uint32_t* num_handles, - bool* no_space, - bool* invalid_message) - : read_any_size_(read_any_size), - may_discard_(may_discard), - num_bytes_(num_bytes), - num_handles_(num_handles), - no_space_(no_space), - invalid_message_(invalid_message) {} - - ~ReadMessageFilter() override {} - - // ports::MessageFilter: - bool Match(const ports::Message& m) override { - const PortsMessage& message = static_cast<const PortsMessage&>(m); - if (message.num_payload_bytes() < sizeof(MessageHeader)) { - *invalid_message_ = true; - return true; - } - - const MessageHeader* header = - static_cast<const MessageHeader*>(message.payload_bytes()); - if (header->header_size > message.num_payload_bytes()) { - *invalid_message_ = true; - return true; - } - - uint32_t bytes_to_read = 0; - uint32_t bytes_available = - static_cast<uint32_t>(message.num_payload_bytes()) - - header->header_size; - if (num_bytes_) { - bytes_to_read = std::min(*num_bytes_, bytes_available); - *num_bytes_ = bytes_available; - } - - uint32_t handles_to_read = 0; - uint32_t handles_available = header->num_dispatchers; - if (num_handles_) { - handles_to_read = std::min(*num_handles_, handles_available); - *num_handles_ = handles_available; - } - - if (handles_to_read < handles_available || - (!read_any_size_ && bytes_to_read < bytes_available)) { - *no_space_ = true; - return may_discard_; - } - - return true; - } - - private: - const bool read_any_size_; - const bool may_discard_; - uint32_t* const num_bytes_; - uint32_t* const num_handles_; - bool* const no_space_; - bool* const invalid_message_; - - DISALLOW_COPY_AND_ASSIGN(ReadMessageFilter); -}; - #if DCHECK_IS_ON() // A MessageFilter which never matches a message. Used to peek at the size of @@ -142,8 +67,8 @@ ~PeekSizeMessageFilter() override {} // ports::MessageFilter: - bool Match(const ports::Message& message) override { - message_size_ = message.num_payload_bytes(); + bool Match(const ports::UserMessageEvent& message) override { + message_size_ = message.GetMessage<UserMessageImpl>()->user_payload_size(); return false; } @@ -211,13 +136,14 @@ } MojoResult MessagePipeDispatcher::WriteMessage( - std::unique_ptr<MessageForTransit> message, + std::unique_ptr<ports::UserMessageEvent> message, MojoWriteMessageFlags flags) { if (port_closed_ || in_transit_) return MOJO_RESULT_INVALID_ARGUMENT; - size_t num_bytes = message->num_bytes(); - int rv = node_controller_->SendMessage(port_, message->TakePortsMessage()); + const size_t num_bytes = + message->GetMessage<UserMessageImpl>()->user_payload_size(); + int rv = node_controller_->SendUserMessage(port_, std::move(message)); DVLOG(4) << "Sent message on pipe " << pipe_id_ << " endpoint " << endpoint_ << " [port=" << port_.name() << "; rv=" << rv @@ -240,7 +166,7 @@ } MojoResult MessagePipeDispatcher::ReadMessage( - std::unique_ptr<MessageForTransit>* message, + std::unique_ptr<ports::UserMessageEvent>* message, uint32_t* num_bytes, MojoHandle* handles, uint32_t* num_handles, @@ -250,9 +176,7 @@ if (port_closed_ || in_transit_) return MOJO_RESULT_INVALID_ARGUMENT; - bool no_space = false; - bool may_discard = flags & MOJO_READ_MESSAGE_FLAG_MAY_DISCARD; - bool invalid_message = false; + const bool may_discard = flags & MOJO_READ_MESSAGE_FLAG_MAY_DISCARD; // Grab a message if the provided handles buffer is large enough. If the input // |num_bytes| is provided and |read_any_size| is false, we also ensure @@ -260,127 +184,16 @@ // // If |read_any_size| is true, the input value of |*num_bytes| is ignored. // This flag exists to support both new and old API behavior. + MojoResult read_result = UserMessageImpl::ReadMessageEventFromPort( + node_controller_, port_, read_any_size, may_discard, num_bytes, handles, + num_handles, message); - ports::ScopedMessage ports_message; - ReadMessageFilter filter(read_any_size, may_discard, num_bytes, num_handles, - &no_space, &invalid_message); - int rv = node_controller_->node()->GetMessage(port_, &ports_message, &filter); + // We may need to update anyone watching our signals in case we just read the + // last available message. + base::AutoLock lock(signal_lock_); + watchers_.NotifyState(GetHandleSignalsStateNoLock()); - if (invalid_message) - return MOJO_RESULT_UNKNOWN; - - if (rv != ports::OK && rv != ports::ERROR_PORT_PEER_CLOSED) { - if (rv == ports::ERROR_PORT_UNKNOWN || - rv == ports::ERROR_PORT_STATE_UNEXPECTED) - return MOJO_RESULT_INVALID_ARGUMENT; - - NOTREACHED(); - return MOJO_RESULT_UNKNOWN; // TODO: Add a better error code here? - } - - if (no_space) { - if (may_discard) { - // May have been the last message on the pipe. Need to update signals just - // in case. - base::AutoLock lock(signal_lock_); - watchers_.NotifyState(GetHandleSignalsStateNoLock()); - } - // |*num_handles| (and/or |*num_bytes| if |read_any_size| is false) wasn't - // sufficient to hold this message's data. The message will still be in - // queue unless MOJO_READ_MESSAGE_FLAG_MAY_DISCARD was set. - return MOJO_RESULT_RESOURCE_EXHAUSTED; - } - - if (!ports_message) { - // No message was available in queue. - - if (rv == ports::OK) - return MOJO_RESULT_SHOULD_WAIT; - - // Peer is closed and there are no more messages to read. - DCHECK_EQ(rv, ports::ERROR_PORT_PEER_CLOSED); - return MOJO_RESULT_FAILED_PRECONDITION; - } - - // Alright! We have a message and the caller has provided sufficient storage - // in which to receive it. - - { - // We need to update anyone watching our signals in case that was the last - // available message. - base::AutoLock lock(signal_lock_); - watchers_.NotifyState(GetHandleSignalsStateNoLock()); - } - - std::unique_ptr<PortsMessage> msg( - static_cast<PortsMessage*>(ports_message.release())); - - const MessageHeader* header = - static_cast<const MessageHeader*>(msg->payload_bytes()); - const DispatcherHeader* dispatcher_headers = - reinterpret_cast<const DispatcherHeader*>(header + 1); - - if (header->num_dispatchers > std::numeric_limits<uint16_t>::max()) - return MOJO_RESULT_UNKNOWN; - - // Deserialize dispatchers. - if (header->num_dispatchers > 0) { - CHECK(handles); - std::vector<DispatcherInTransit> dispatchers(header->num_dispatchers); - size_t data_payload_index = sizeof(MessageHeader) + - header->num_dispatchers * sizeof(DispatcherHeader); - if (data_payload_index > header->header_size) - return MOJO_RESULT_UNKNOWN; - const char* dispatcher_data = reinterpret_cast<const char*>( - dispatcher_headers + header->num_dispatchers); - size_t port_index = 0; - size_t platform_handle_index = 0; - ScopedPlatformHandleVectorPtr msg_handles = msg->TakeHandles(); - const size_t num_msg_handles = msg_handles ? msg_handles->size() : 0; - for (size_t i = 0; i < header->num_dispatchers; ++i) { - const DispatcherHeader& dh = dispatcher_headers[i]; - Type type = static_cast<Type>(dh.type); - - size_t next_payload_index = data_payload_index + dh.num_bytes; - if (msg->num_payload_bytes() < next_payload_index || - next_payload_index < data_payload_index) { - return MOJO_RESULT_UNKNOWN; - } - - size_t next_port_index = port_index + dh.num_ports; - if (msg->num_ports() < next_port_index || next_port_index < port_index) - return MOJO_RESULT_UNKNOWN; - - size_t next_platform_handle_index = - platform_handle_index + dh.num_platform_handles; - if (num_msg_handles < next_platform_handle_index || - next_platform_handle_index < platform_handle_index) { - return MOJO_RESULT_UNKNOWN; - } - - PlatformHandle* out_handles = - num_msg_handles ? msg_handles->data() + platform_handle_index - : nullptr; - dispatchers[i].dispatcher = Dispatcher::Deserialize( - type, dispatcher_data, dh.num_bytes, msg->ports() + port_index, - dh.num_ports, out_handles, dh.num_platform_handles); - if (!dispatchers[i].dispatcher) - return MOJO_RESULT_UNKNOWN; - - dispatcher_data += dh.num_bytes; - data_payload_index = next_payload_index; - port_index = next_port_index; - platform_handle_index = next_platform_handle_index; - } - - if (!node_controller_->core()->AddDispatchersFromTransit(dispatchers, - handles)) - return MOJO_RESULT_UNKNOWN; - } - - CHECK(msg); - *message = MessageForTransit::WrapPortsMessage(std::move(msg)); - return MOJO_RESULT_OK; + return read_result; } HandleSignalsState @@ -533,7 +346,7 @@ ports::PortStatus port_status; if (node_controller_->node()->GetStatus(port_, &port_status) == ports::OK) { if (port_status.has_messages) { - ports::ScopedMessage unused; + std::unique_ptr<ports::UserMessageEvent> unused; PeekSizeMessageFilter filter; node_controller_->node()->GetMessage(port_, &unused, &filter); DVLOG(4) << "New message detected on message pipe " << pipe_id_
diff --git a/mojo/edk/system/message_pipe_dispatcher.h b/mojo/edk/system/message_pipe_dispatcher.h index 574ad660..6425f308 100644 --- a/mojo/edk/system/message_pipe_dispatcher.h +++ b/mojo/edk/system/message_pipe_dispatcher.h
@@ -13,7 +13,6 @@ #include "base/macros.h" #include "mojo/edk/system/atomic_flag.h" #include "mojo/edk/system/dispatcher.h" -#include "mojo/edk/system/message_for_transit.h" #include "mojo/edk/system/ports/port_ref.h" #include "mojo/edk/system/watcher_set.h" @@ -48,9 +47,9 @@ // Dispatcher: Type GetType() const override; MojoResult Close() override; - MojoResult WriteMessage(std::unique_ptr<MessageForTransit> message, + MojoResult WriteMessage(std::unique_ptr<ports::UserMessageEvent> message, MojoWriteMessageFlags flags) override; - MojoResult ReadMessage(std::unique_ptr<MessageForTransit>* message, + MojoResult ReadMessage(std::unique_ptr<ports::UserMessageEvent>* message, uint32_t* num_bytes, MojoHandle* handles, uint32_t* num_handles,
diff --git a/mojo/edk/system/node_channel.cc b/mojo/edk/system/node_channel.cc index d0e25c5..813a01d 100644 --- a/mojo/edk/system/node_channel.cc +++ b/mojo/edk/system/node_channel.cc
@@ -30,16 +30,16 @@ ADD_BROKER_CLIENT, BROKER_CLIENT_ADDED, ACCEPT_BROKER_CLIENT, - PORTS_MESSAGE, + EVENT_MESSAGE, REQUEST_PORT_MERGE, REQUEST_INTRODUCTION, INTRODUCE, #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) - RELAY_PORTS_MESSAGE, + RELAY_EVENT_MESSAGE, #endif - BROADCAST, + BROADCAST_EVENT, #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) - PORTS_MESSAGE_FROM_RELAY, + EVENT_MESSAGE_FROM_RELAY, #endif ACCEPT_PEER, }; @@ -113,12 +113,12 @@ #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) // This struct is followed by the full payload of a message to be relayed. -struct RelayPortsMessageData { +struct RelayEventMessageData { ports::NodeName destination; }; // This struct is followed by the full payload of a relayed message. -struct PortsMessageFromRelayData { +struct EventMessageFromRelayData { ports::NodeName source; }; #endif @@ -167,17 +167,19 @@ } // static -Channel::MessagePtr NodeChannel::CreatePortsMessage(size_t payload_size, +Channel::MessagePtr NodeChannel::CreateEventMessage(size_t payload_size, void** payload, size_t num_handles) { - return CreateMessage(MessageType::PORTS_MESSAGE, payload_size, num_handles, + return CreateMessage(MessageType::EVENT_MESSAGE, payload_size, num_handles, payload); } // static -void NodeChannel::GetPortsMessageData(Channel::Message* message, +void NodeChannel::GetEventMessageData(Channel::Message* message, void** data, size_t* num_data_bytes) { + // NOTE: OnChannelMessage guarantees that we never accept a Channel::Message + // with a payload of fewer than |sizeof(Header)| bytes. *data = reinterpret_cast<Header*>(message->mutable_payload()) + 1; *num_data_bytes = message->payload_size() - sizeof(Header); } @@ -342,10 +344,6 @@ WriteChannelMessage(std::move(message)); } -void NodeChannel::PortsMessage(Channel::MessagePtr message) { - WriteChannelMessage(std::move(message)); -} - void NodeChannel::RequestPortMerge(const ports::PortName& connector_port_name, const std::string& token) { RequestPortMergeData* data; @@ -378,17 +376,21 @@ WriteChannelMessage(std::move(message)); } +void NodeChannel::SendChannelMessage(Channel::MessagePtr message) { + WriteChannelMessage(std::move(message)); +} + void NodeChannel::Broadcast(Channel::MessagePtr message) { DCHECK(!message->has_handles()); void* data; Channel::MessagePtr broadcast_message = CreateMessage( - MessageType::BROADCAST, message->data_num_bytes(), 0, &data); + MessageType::BROADCAST_EVENT, message->data_num_bytes(), 0, &data); memcpy(data, message->data(), message->data_num_bytes()); WriteChannelMessage(std::move(broadcast_message)); } #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) -void NodeChannel::RelayPortsMessage(const ports::NodeName& destination, +void NodeChannel::RelayEventMessage(const ports::NodeName& destination, Channel::MessagePtr message) { #if defined(OS_WIN) DCHECK(message->has_handles()); @@ -396,10 +398,10 @@ // Note that this is only used on Windows, and on Windows all platform // handles are included in the message data. We blindly copy all the data // here and the relay node (the parent) will duplicate handles as needed. - size_t num_bytes = sizeof(RelayPortsMessageData) + message->data_num_bytes(); - RelayPortsMessageData* data; - Channel::MessagePtr relay_message = CreateMessage( - MessageType::RELAY_PORTS_MESSAGE, num_bytes, 0, &data); + size_t num_bytes = sizeof(RelayEventMessageData) + message->data_num_bytes(); + RelayEventMessageData* data; + Channel::MessagePtr relay_message = + CreateMessage(MessageType::RELAY_EVENT_MESSAGE, num_bytes, 0, &data); data->destination = destination; memcpy(data + 1, message->data(), message->data_num_bytes()); @@ -419,10 +421,10 @@ // message may contain fds which need to be attached to the outer message so // that they can be transferred to the broker. ScopedPlatformHandleVectorPtr handles = message->TakeHandles(); - size_t num_bytes = sizeof(RelayPortsMessageData) + message->data_num_bytes(); - RelayPortsMessageData* data; + size_t num_bytes = sizeof(RelayEventMessageData) + message->data_num_bytes(); + RelayEventMessageData* data; Channel::MessagePtr relay_message = CreateMessage( - MessageType::RELAY_PORTS_MESSAGE, num_bytes, handles->size(), &data); + MessageType::RELAY_EVENT_MESSAGE, num_bytes, handles->size(), &data); data->destination = destination; memcpy(data + 1, message->data(), message->data_num_bytes()); relay_message->SetHandles(std::move(handles)); @@ -431,14 +433,14 @@ WriteChannelMessage(std::move(relay_message)); } -void NodeChannel::PortsMessageFromRelay(const ports::NodeName& source, +void NodeChannel::EventMessageFromRelay(const ports::NodeName& source, Channel::MessagePtr message) { - size_t num_bytes = sizeof(PortsMessageFromRelayData) + - message->payload_size(); - PortsMessageFromRelayData* data; - Channel::MessagePtr relayed_message = CreateMessage( - MessageType::PORTS_MESSAGE_FROM_RELAY, num_bytes, message->num_handles(), - &data); + size_t num_bytes = + sizeof(EventMessageFromRelayData) + message->payload_size(); + EventMessageFromRelayData* data; + Channel::MessagePtr relayed_message = + CreateMessage(MessageType::EVENT_MESSAGE_FROM_RELAY, num_bytes, + message->num_handles(), &data); data->source = source; if (message->payload_size()) memcpy(data + 1, message->payload(), message->payload_size()); @@ -504,7 +506,7 @@ #elif defined(OS_MACOSX) && !defined(OS_IOS) // If we're not the root, receive any mach ports from the message. If we're // the root, the only message containing mach ports should be a - // RELAY_PORTS_MESSAGE. + // RELAY_EVENT_MESSAGE. { MachPortRelay* relay = delegate_->GetMachPortRelay(); if (handles && !relay) { @@ -605,13 +607,13 @@ break; } - case MessageType::PORTS_MESSAGE: { + case MessageType::EVENT_MESSAGE: { size_t num_handles = handles ? handles->size() : 0; Channel::MessagePtr message( new Channel::Message(payload_size, num_handles)); message->SetHandles(std::move(handles)); memcpy(message->mutable_payload(), payload, payload_size); - delegate_->OnPortsMessage(remote_node_name_, std::move(message)); + delegate_->OnEventMessage(remote_node_name_, std::move(message)); return; } @@ -659,16 +661,16 @@ } #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) - case MessageType::RELAY_PORTS_MESSAGE: { + case MessageType::RELAY_EVENT_MESSAGE: { base::ProcessHandle from_process; { base::AutoLock lock(remote_process_handle_lock_); from_process = remote_process_handle_; } - const RelayPortsMessageData* data; + const RelayEventMessageData* data; if (GetMessagePayload(payload, payload_size, &data)) { // Don't try to relay an empty message. - if (payload_size <= sizeof(Header) + sizeof(RelayPortsMessageData)) + if (payload_size <= sizeof(Header) + sizeof(RelayEventMessageData)) break; const void* message_start = data + 1; @@ -696,7 +698,7 @@ } } #endif - delegate_->OnRelayPortsMessage(remote_node_name_, from_process, + delegate_->OnRelayEventMessage(remote_node_name_, from_process, data->destination, std::move(message)); return; } @@ -704,7 +706,7 @@ } #endif - case MessageType::BROADCAST: { + case MessageType::BROADCAST_EVENT: { if (payload_size <= sizeof(Header)) break; const void* data = static_cast<const void*>( @@ -720,8 +722,8 @@ } #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) - case MessageType::PORTS_MESSAGE_FROM_RELAY: - const PortsMessageFromRelayData* data; + case MessageType::EVENT_MESSAGE_FROM_RELAY: + const EventMessageFromRelayData* data; if (GetMessagePayload(payload, payload_size, &data)) { size_t num_bytes = payload_size - sizeof(*data); if (num_bytes < sizeof(Header)) @@ -734,8 +736,8 @@ message->SetHandles(std::move(handles)); if (num_bytes) memcpy(message->mutable_payload(), data + 1, num_bytes); - delegate_->OnPortsMessageFromRelay( - remote_node_name_, data->source, std::move(message)); + delegate_->OnEventMessageFromRelay(remote_node_name_, data->source, + std::move(message)); return; } break; @@ -821,7 +823,7 @@ ports::NodeName destination = pending_relays.front().first; Channel::MessagePtr message = std::move(pending_relays.front().second); pending_relays.pop(); - delegate_->OnRelayPortsMessage(remote_node_name_, remote_process_handle, + delegate_->OnRelayEventMessage(remote_node_name_, remote_process_handle, destination, std::move(message)); } } @@ -831,7 +833,7 @@ #if defined(OS_WIN) // Map handles to the destination process. Note: only messages from a // privileged node should contain handles on Windows. If an unprivileged - // node needs to send handles, it should do so via RelayPortsMessage which + // node needs to send handles, it should do so via RelayEventMessage which // stashes the handles in the message in such a way that they go undetected // here (they'll be unpacked and duplicated by a privileged parent.)
diff --git a/mojo/edk/system/node_channel.h b/mojo/edk/system/node_channel.h index 95dc3410..9ca2eb9 100644 --- a/mojo/edk/system/node_channel.h +++ b/mojo/edk/system/node_channel.h
@@ -56,7 +56,7 @@ virtual void OnAcceptBrokerClient(const ports::NodeName& from_node, const ports::NodeName& broker_name, ScopedPlatformHandle broker_channel) = 0; - virtual void OnPortsMessage(const ports::NodeName& from_node, + virtual void OnEventMessage(const ports::NodeName& from_node, Channel::MessagePtr message) = 0; virtual void OnRequestPortMerge(const ports::NodeName& from_node, const ports::PortName& connector_port_name, @@ -69,11 +69,11 @@ virtual void OnBroadcast(const ports::NodeName& from_node, Channel::MessagePtr message) = 0; #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) - virtual void OnRelayPortsMessage(const ports::NodeName& from_node, + virtual void OnRelayEventMessage(const ports::NodeName& from_node, base::ProcessHandle from_process, const ports::NodeName& destination, Channel::MessagePtr message) = 0; - virtual void OnPortsMessageFromRelay(const ports::NodeName& from_node, + virtual void OnEventMessageFromRelay(const ports::NodeName& from_node, const ports::NodeName& source_node, Channel::MessagePtr message) = 0; #endif @@ -95,11 +95,12 @@ scoped_refptr<base::TaskRunner> io_task_runner, const ProcessErrorCallback& process_error_callback); - static Channel::MessagePtr CreatePortsMessage(size_t payload_size, + static Channel::MessagePtr CreateEventMessage(size_t payload_size, void** payload, size_t num_handles); - static void GetPortsMessageData(Channel::Message* message, void** data, + static void GetEventMessageData(Channel::Message* message, + void** data, size_t* num_data_bytes); // Start receiving messages. @@ -137,12 +138,12 @@ ScopedPlatformHandle broker_channel); void AcceptBrokerClient(const ports::NodeName& broker_name, ScopedPlatformHandle broker_channel); - void PortsMessage(Channel::MessagePtr message); void RequestPortMerge(const ports::PortName& connector_port_name, const std::string& token); void RequestIntroduction(const ports::NodeName& name); void Introduce(const ports::NodeName& name, ScopedPlatformHandle channel_handle); + void SendChannelMessage(Channel::MessagePtr message); void Broadcast(Channel::MessagePtr message); #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) @@ -150,13 +151,13 @@ // pass windows handles between two processes that do not have permission to // duplicate handles into the other's address space. The relay process is // assumed to have that permission. - void RelayPortsMessage(const ports::NodeName& destination, + void RelayEventMessage(const ports::NodeName& destination, Channel::MessagePtr message); // Sends a message to its destination from a relay. This is interpreted by the - // receiver similarly to PortsMessage, but the original source node is + // receiver similarly to EventMessage, but the original source node is // provided as additional message metadata from the (trusted) relay node. - void PortsMessageFromRelay(const ports::NodeName& source, + void EventMessageFromRelay(const ports::NodeName& source, Channel::MessagePtr message); #endif
diff --git a/mojo/edk/system/node_controller.cc b/mojo/edk/system/node_controller.cc index 477d350b..c895379 100644 --- a/mojo/edk/system/node_controller.cc +++ b/mojo/edk/system/node_controller.cc
@@ -25,8 +25,8 @@ #include "mojo/edk/system/broker_host.h" #include "mojo/edk/system/configuration.h" #include "mojo/edk/system/core.h" -#include "mojo/edk/system/ports_message.h" #include "mojo/edk/system/request_context.h" +#include "mojo/edk/system/user_message_impl.h" #if defined(OS_MACOSX) && !defined(OS_IOS) #include "mojo/edk/system/mach_port_relay.h" @@ -77,25 +77,49 @@ 50 /* bucket count */); } -bool ParsePortsMessage(Channel::Message* message, - void** data, - size_t* num_data_bytes, - size_t* num_header_bytes, - size_t* num_payload_bytes, - size_t* num_ports_bytes) { - DCHECK(data && num_data_bytes && num_header_bytes && num_payload_bytes && - num_ports_bytes); - - NodeChannel::GetPortsMessageData(message, data, num_data_bytes); - if (!*num_data_bytes) - return false; - - if (!ports::Message::Parse(*data, *num_data_bytes, num_header_bytes, - num_payload_bytes, num_ports_bytes)) { - return false; +Channel::MessagePtr SerializeEventMessage(ports::ScopedEvent event) { + if (event->type() == ports::Event::Type::kUserMessage) { + // User message events may already be serialized or need to perform some + // custom-bound serialization routines. + return UserMessageImpl::SerializeEventMessage( + ports::Event::Cast<ports::UserMessageEvent>(&event)); } - return true; + void* data; + auto message = + NodeChannel::CreateEventMessage(event->GetSerializedSize(), &data, 0); + event->Serialize(data); + return message; +} + +ports::ScopedEvent DeserializeEventMessage( + const ports::NodeName& from_node, + Channel::MessagePtr channel_message) { + void* data; + size_t size; + NodeChannel::GetEventMessageData(channel_message.get(), &data, &size); + auto event = ports::Event::Deserialize(data, size); + if (!event) + return nullptr; + + if (event->type() != ports::Event::Type::kUserMessage) + return event; + + // User messages require extra parsing. + const size_t event_size = event->GetSerializedSize(); + + // Note that if this weren't true, the event couldn't have been deserialized + // in the first place. + DCHECK_LE(event_size, size); + + auto message = UserMessageImpl::CreateFromChannelMessage( + std::move(channel_message), static_cast<uint8_t*>(data) + event_size, + size - event_size); + message->set_source_node(from_node); + + auto message_event = ports::Event::Cast<ports::UserMessageEvent>(&event); + message_event->AttachMessage(std::move(message)); + return std::move(message_event); } // Used by NodeController to watch for shutdown. Since no IO can happen once @@ -266,11 +290,10 @@ AcceptIncomingMessages(); } -int NodeController::SendMessage(const ports::PortRef& port, - std::unique_ptr<PortsMessage> message) { - ports::ScopedMessage ports_message(message.release()); - int rv = node_->SendMessage(port, std::move(ports_message)); - +int NodeController::SendUserMessage( + const ports::PortRef& port, + std::unique_ptr<ports::UserMessageEvent> message) { + int rv = node_->SendUserMessage(port, std::move(message)); AcceptIncomingMessages(); return rv; } @@ -519,7 +542,7 @@ // Flush any queued message we need to deliver to this node. while (!pending_messages.empty()) { - channel->PortsMessage(std::move(pending_messages.front())); + channel->SendChannelMessage(std::move(pending_messages.front())); pending_messages.pop(); } } @@ -584,30 +607,28 @@ AcceptIncomingMessages(); } -void NodeController::SendPeerMessage(const ports::NodeName& name, - ports::ScopedMessage message) { - Channel::MessagePtr channel_message = - static_cast<PortsMessage*>(message.get())->TakeChannelMessage(); - +void NodeController::SendPeerEvent(const ports::NodeName& name, + ports::ScopedEvent event) { + Channel::MessagePtr event_message = SerializeEventMessage(std::move(event)); scoped_refptr<NodeChannel> peer = GetPeerChannel(name); #if defined(OS_WIN) - if (channel_message->has_handles()) { + if (event_message->has_handles()) { // If we're sending a message with handles we aren't the destination // node's parent or broker (i.e. we don't know its process handle), ask // the broker to relay for us. scoped_refptr<NodeChannel> broker = GetBrokerChannel(); if (!peer || !peer->HasRemoteProcessHandle()) { if (!GetConfiguration().is_broker_process && broker) { - broker->RelayPortsMessage(name, std::move(channel_message)); + broker->RelayEventMessage(name, std::move(event_message)); } else { base::AutoLock lock(broker_lock_); - pending_relay_messages_[name].emplace(std::move(channel_message)); + pending_relay_messages_[name].emplace(std::move(event_message)); } return; } } #elif defined(OS_MACOSX) && !defined(OS_IOS) - if (channel_message->has_mach_ports()) { + if (event_message->has_mach_ports()) { // Messages containing Mach ports are always routed through the broker, even // if the broker process is the intended recipient. bool use_broker = false; @@ -620,10 +641,10 @@ if (use_broker) { scoped_refptr<NodeChannel> broker = GetBrokerChannel(); if (broker) { - broker->RelayPortsMessage(name, std::move(channel_message)); + broker->RelayEventMessage(name, std::move(event_message)); } else { base::AutoLock lock(broker_lock_); - pending_relay_messages_[name].emplace(std::move(channel_message)); + pending_relay_messages_[name].emplace(std::move(event_message)); } return; } @@ -631,7 +652,7 @@ #endif // defined(OS_WIN) if (peer) { - peer->PortsMessage(std::move(channel_message)); + peer->SendChannelMessage(std::move(event_message)); return; } @@ -651,7 +672,7 @@ base::AutoLock lock(peers_lock_); auto& queue = pending_peer_messages_[name]; needs_introduction = queue.empty(); - queue.emplace(std::move(channel_message)); + queue.emplace(std::move(event_message)); } if (needs_introduction) broker->RequestIntroduction(name); @@ -660,47 +681,42 @@ void NodeController::AcceptIncomingMessages() { // This is an impactically large value which should never be reached in // practice. See the CHECK below for usage. - constexpr size_t kMaxAcceptedMessages = 1000000; + constexpr size_t kMaxAcceptedEvents = 1000000; - size_t num_messages_accepted = 0; - while (incoming_messages_flag_) { + size_t num_events_accepted = 0; + while (incoming_events_flag_) { // TODO: We may need to be more careful to avoid starving the rest of the // thread here. Revisit this if it turns out to be a problem. One // alternative would be to schedule a task to continue pumping messages // after flushing once. - messages_lock_.Acquire(); - if (incoming_messages_.empty()) { - messages_lock_.Release(); + events_lock_.Acquire(); + if (incoming_events_.empty()) { + events_lock_.Release(); break; } - // libstdc++'s deque creates an internal buffer on construction, even when - // the size is 0. So avoid creating it until it is necessary. - std::queue<ports::ScopedMessage> messages; - std::swap(messages, incoming_messages_); - incoming_messages_flag_.Set(false); - messages_lock_.Release(); + std::vector<ports::ScopedEvent> events; + std::swap(events, incoming_events_); + incoming_events_flag_.Set(false); + events_lock_.Release(); - num_messages_accepted += messages.size(); - while (!messages.empty()) { - node_->AcceptMessage(std::move(messages.front())); - messages.pop(); - } + num_events_accepted += events.size(); + for (auto& event : events) + node_->AcceptEvent(std::move(event)); // This is effectively a safeguard against potential bugs which might lead // to runaway message cycles. If any such cycles arise, we'll start seeing // crash reports from this location. - CHECK_LE(num_messages_accepted, kMaxAcceptedMessages); + CHECK_LE(num_events_accepted, kMaxAcceptedEvents); } - if (num_messages_accepted >= 4) { + if (num_events_accepted >= 4) { // Note: We avoid logging this histogram for the vast majority of cases. // See https://crbug.com/685763 for more context. UMA_HISTOGRAM_CUSTOM_COUNTS("Mojo.System.MessagesAcceptedPerEvent", - static_cast<int32_t>(num_messages_accepted), - 1 /* min */, - 500 /* max */, + static_cast<int32_t>(num_events_accepted), + 1 /* min */, 500 /* max */, 50 /* bucket count */); } @@ -711,12 +727,12 @@ RequestContext request_context(RequestContext::Source::SYSTEM); { - base::AutoLock lock(messages_lock_); - // Allow a new incoming messages processing task to be posted. This can't be - // done after AcceptIncomingMessages() otherwise a message might be missed. + base::AutoLock lock(events_lock_); + // Allow a new incoming event processing task to be posted. This can't be + // done after AcceptIncomingMessages() otherwise an event might be missed. // Doing it here may result in at most two tasks existing at the same time; // this running one, and one pending in the task runner. - incoming_messages_task_posted_ = false; + incoming_events_task_posted_ = false; } AcceptIncomingMessages(); @@ -762,40 +778,35 @@ GenerateRandomName(port_name); } -void NodeController::AllocMessage(size_t num_header_bytes, - ports::ScopedMessage* message) { - message->reset(new PortsMessage(num_header_bytes, 0, 0, nullptr)); -} - -void NodeController::ForwardMessage(const ports::NodeName& node, - ports::ScopedMessage message) { - DCHECK(message); +void NodeController::ForwardEvent(const ports::NodeName& node, + ports::ScopedEvent event) { + DCHECK(event); bool schedule_pump_task = false; if (node == name_) { // NOTE: We need to avoid re-entering the Node instance within - // ForwardMessage. Because ForwardMessage is only ever called - // (synchronously) in response to Node's ClosePort, SendMessage, or - // AcceptMessage, we flush the queue after calling any of those methods. - base::AutoLock lock(messages_lock_); + // ForwardEvent. Because ForwardEvent is only ever called + // (synchronously) in response to Node's ClosePort, SendUserMessage, or + // AcceptEvent, we flush the queue after calling any of those methods. + base::AutoLock lock(events_lock_); // |io_task_runner_| may be null in tests or processes that don't require // multi-process Mojo. - schedule_pump_task = incoming_messages_.empty() && io_task_runner_ && - !incoming_messages_task_posted_; - incoming_messages_task_posted_ |= schedule_pump_task; - incoming_messages_.emplace(std::move(message)); - incoming_messages_flag_.Set(true); + schedule_pump_task = incoming_events_.empty() && io_task_runner_ && + !incoming_events_task_posted_; + incoming_events_task_posted_ |= schedule_pump_task; + incoming_events_.emplace_back(std::move(event)); + incoming_events_flag_.Set(true); } else { - SendPeerMessage(node, std::move(message)); + SendPeerEvent(node, std::move(event)); } if (schedule_pump_task) { // Normally, the queue is processed after the action that added the local - // message is done (i.e. SendMessage, ClosePort, etc). However, it's also - // possible for a local message to be added as a result of a remote message, - // and OnChannelMessage() doesn't process this queue (although - // OnPortsMessage() does). There may also be other code paths, now or added - // in the future, which cause local messages to be added but don't process - // this message queue. + // event is done (i.e. SendUserMessage, ClosePort, etc). However, it's also + // possible for a local event to be added as a result of a remote event, and + // OnChannelMessage() doesn't process this queue (although OnEventMessage() + // does.) There may also be other code paths, now or added in the future, + // which cause local messages to be added but don't process this message + // queue. // // Instead of adding a call to AcceptIncomingMessages() on every possible // code path, post a task to the IO thread to process the queue. If the @@ -807,11 +818,9 @@ } } -void NodeController::BroadcastMessage(ports::ScopedMessage message) { - CHECK_EQ(message->num_ports(), 0u); - Channel::MessagePtr channel_message = - static_cast<PortsMessage*>(message.get())->TakeChannelMessage(); - CHECK(!channel_message->has_handles()); +void NodeController::BroadcastEvent(ports::ScopedEvent event) { + Channel::MessagePtr channel_message = SerializeEventMessage(std::move(event)); + DCHECK(!channel_message->has_handles()); scoped_refptr<NodeChannel> broker = GetBrokerChannel(); if (broker) @@ -1060,7 +1069,7 @@ const ports::NodeName& destination = entry.first; auto& message_queue = entry.second; while (!message_queue.empty()) { - broker->RelayPortsMessage(destination, std::move(message_queue.front())); + broker->RelayEventMessage(destination, std::move(message_queue.front())); message_queue.pop(); } } @@ -1069,27 +1078,19 @@ DVLOG(1) << "Child " << name_ << " accepted by broker " << broker_name; } -void NodeController::OnPortsMessage(const ports::NodeName& from_node, +void NodeController::OnEventMessage(const ports::NodeName& from_node, Channel::MessagePtr channel_message) { DCHECK(io_task_runner_->RunsTasksInCurrentSequence()); - void* data; - size_t num_data_bytes, num_header_bytes, num_payload_bytes, num_ports_bytes; - if (!ParsePortsMessage(channel_message.get(), &data, &num_data_bytes, - &num_header_bytes, &num_payload_bytes, - &num_ports_bytes)) { - DropPeer(from_node, nullptr); + auto event = DeserializeEventMessage(from_node, std::move(channel_message)); + if (!event) { + // We silently ignore unparseable events, as they may come from a process + // running a newer version of Mojo. + DVLOG(1) << "Ignoring invalid or unknown event from " << from_node; return; } - CHECK(channel_message); - std::unique_ptr<PortsMessage> ports_message( - new PortsMessage(num_header_bytes, - num_payload_bytes, - num_ports_bytes, - std::move(channel_message))); - ports_message->set_source_node(from_node); - node_->AcceptMessage(ports::ScopedMessage(ports_message.release())); + node_->AcceptEvent(std::move(event)); AcceptIncomingMessages(); } @@ -1182,34 +1183,33 @@ Channel::MessagePtr message) { DCHECK(!message->has_handles()); - void* data; - size_t num_data_bytes, num_header_bytes, num_payload_bytes, num_ports_bytes; - if (!ParsePortsMessage(message.get(), &data, &num_data_bytes, - &num_header_bytes, &num_payload_bytes, - &num_ports_bytes)) { - DropPeer(from_node, nullptr); - return; - } - - // Broadcast messages must not contain ports. - if (num_ports_bytes > 0) { - DropPeer(from_node, nullptr); + auto event = DeserializeEventMessage(from_node, std::move(message)); + if (!event) { + // We silently ignore unparseable events, as they may come from a process + // running a newer version of Mojo. + DVLOG(1) << "Ignoring request to broadcast invalid or unknown event from " + << from_node; return; } base::AutoLock lock(peers_lock_); for (auto& iter : peers_) { - // Copy and send the message to each known peer. - Channel::MessagePtr peer_message( - new Channel::Message(message->payload_size(), 0)); - memcpy(peer_message->mutable_payload(), message->payload(), - message->payload_size()); - iter.second->PortsMessage(std::move(peer_message)); + // Clone and send the event to each known peer. Events which cannot be + // cloned cannot be broadcast. + ports::ScopedEvent clone = event->Clone(); + if (!clone) { + DVLOG(1) << "Ignoring request to broadcast invalid event from " + << from_node << " [type=" << static_cast<uint32_t>(event->type()) + << "]"; + return; + } + + iter.second->SendChannelMessage(SerializeEventMessage(std::move(clone))); } } #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) -void NodeController::OnRelayPortsMessage(const ports::NodeName& from_node, +void NodeController::OnRelayEventMessage(const ports::NodeName& from_node, base::ProcessHandle from_process, const ports::NodeName& destination, Channel::MessagePtr message) { @@ -1263,18 +1263,18 @@ if (destination == name_) { // Great, we can deliver this message locally. - OnPortsMessage(from_node, std::move(message)); + OnEventMessage(from_node, std::move(message)); return; } scoped_refptr<NodeChannel> peer = GetPeerChannel(destination); if (peer) - peer->PortsMessageFromRelay(from_node, std::move(message)); + peer->EventMessageFromRelay(from_node, std::move(message)); else DLOG(ERROR) << "Dropping relay message for unknown node " << destination; } -void NodeController::OnPortsMessageFromRelay(const ports::NodeName& from_node, +void NodeController::OnEventMessageFromRelay(const ports::NodeName& from_node, const ports::NodeName& source_node, Channel::MessagePtr message) { if (GetPeerChannel(from_node) != GetBrokerChannel()) { @@ -1283,7 +1283,7 @@ return; } - OnPortsMessage(source_node, std::move(message)); + OnEventMessage(source_node, std::move(message)); } #endif
diff --git a/mojo/edk/system/node_controller.h b/mojo/edk/system/node_controller.h index f5eed33e..9d1c816 100644 --- a/mojo/edk/system/node_controller.h +++ b/mojo/edk/system/node_controller.h
@@ -24,6 +24,7 @@ #include "mojo/edk/embedder/scoped_platform_handle.h" #include "mojo/edk/system/atomic_flag.h" #include "mojo/edk/system/node_channel.h" +#include "mojo/edk/system/ports/event.h" #include "mojo/edk/system/ports/name.h" #include "mojo/edk/system/ports/node.h" #include "mojo/edk/system/ports/node_delegate.h" @@ -38,7 +39,6 @@ class Broker; class Core; class MachPortRelay; -class PortsMessage; // The owner of ports::Node which facilitates core EDK implementation. All // public interface methods are safe to call from any thread. @@ -103,8 +103,8 @@ void ClosePort(const ports::PortRef& port); // Sends a message on a port to its peer. - int SendMessage(const ports::PortRef& port_ref, - std::unique_ptr<PortsMessage> message); + int SendUserMessage(const ports::PortRef& port_ref, + std::unique_ptr<ports::UserMessageEvent> message); // Merges a local port |port| into a port reserved by |name| in the parent. void MergePortIntoParent(const std::string& name, const ports::PortRef& port); @@ -176,19 +176,16 @@ scoped_refptr<NodeChannel> channel, bool start_channel); void DropPeer(const ports::NodeName& name, NodeChannel* channel); - void SendPeerMessage(const ports::NodeName& name, - ports::ScopedMessage message); + void SendPeerEvent(const ports::NodeName& name, ports::ScopedEvent event); void AcceptIncomingMessages(); void ProcessIncomingMessages(); void DropAllPeers(); // ports::NodeDelegate: void GenerateRandomPortName(ports::PortName* port_name) override; - void AllocMessage(size_t num_header_bytes, - ports::ScopedMessage* message) override; - void ForwardMessage(const ports::NodeName& node, - ports::ScopedMessage message) override; - void BroadcastMessage(ports::ScopedMessage message) override; + void ForwardEvent(const ports::NodeName& node, + ports::ScopedEvent event) override; + void BroadcastEvent(ports::ScopedEvent event) override; void PortStatusChanged(const ports::PortRef& port) override; // NodeChannel::Delegate: @@ -207,7 +204,7 @@ void OnAcceptBrokerClient(const ports::NodeName& from_node, const ports::NodeName& broker_name, ScopedPlatformHandle broker_channel) override; - void OnPortsMessage(const ports::NodeName& from_node, + void OnEventMessage(const ports::NodeName& from_node, Channel::MessagePtr message) override; void OnRequestPortMerge(const ports::NodeName& from_node, const ports::PortName& connector_port_name, @@ -220,11 +217,11 @@ void OnBroadcast(const ports::NodeName& from_node, Channel::MessagePtr message) override; #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) - void OnRelayPortsMessage(const ports::NodeName& from_node, + void OnRelayEventMessage(const ports::NodeName& from_node, base::ProcessHandle from_process, const ports::NodeName& destination, Channel::MessagePtr message) override; - void OnPortsMessageFromRelay(const ports::NodeName& from_node, + void OnEventMessageFromRelay(const ports::NodeName& from_node, const ports::NodeName& source_node, Channel::MessagePtr message) override; #endif @@ -311,14 +308,14 @@ std::unordered_map<ports::NodeName, OutgoingMessageQueue> pending_relay_messages_; - // Guards |incoming_messages_| and |incoming_messages_task_posted_|. - base::Lock messages_lock_; - std::queue<ports::ScopedMessage> incoming_messages_; + // Guards |incoming_events_| and |incoming_events_task_posted_|. + base::Lock events_lock_; + std::vector<ports::ScopedEvent> incoming_events_; // Ensures that there is only one incoming messages task posted to the IO // thread. - bool incoming_messages_task_posted_ = false; - // Flag to fast-path checking |incoming_messages_|. - AtomicFlag incoming_messages_flag_; + bool incoming_events_task_posted_ = false; + // Flag to fast-path checking |incoming_events_|. + AtomicFlag incoming_events_flag_; // Guards |shutdown_callback_|. base::Lock shutdown_lock_;
diff --git a/mojo/edk/system/ports/BUILD.gn b/mojo/edk/system/ports/BUILD.gn index 5c82761..b5562d0 100644 --- a/mojo/edk/system/ports/BUILD.gn +++ b/mojo/edk/system/ports/BUILD.gn
@@ -8,8 +8,6 @@ sources = [ "event.cc", "event.h", - "message.cc", - "message.h", "message_filter.h", "message_queue.cc", "message_queue.h", @@ -23,6 +21,7 @@ "port_ref.cc", "port_ref.h", "user_data.h", + "user_message.h", ] public_deps = [
diff --git a/mojo/edk/system/ports/event.cc b/mojo/edk/system/ports/event.cc index 2e22086..78a2168dc 100644 --- a/mojo/edk/system/ports/event.cc +++ b/mojo/edk/system/ports/event.cc
@@ -4,8 +4,12 @@ #include "mojo/edk/system/ports/event.h" +#include <stdint.h> #include <string.h> +#include "base/numerics/safe_math.h" +#include "mojo/edk/system/ports/user_message.h" + namespace mojo { namespace edk { namespace ports { @@ -14,13 +18,49 @@ const size_t kPortsMessageAlignment = 8; -static_assert(sizeof(PortDescriptor) % kPortsMessageAlignment == 0, +#pragma pack(push, 1) + +struct SerializedHeader { + Event::Type type; + uint32_t padding; + PortName port_name; +}; + +struct UserMessageEventData { + uint64_t sequence_num; + uint32_t num_ports; + uint32_t padding; +}; + +struct ObserveProxyEventData { + NodeName proxy_node_name; + PortName proxy_port_name; + NodeName proxy_target_node_name; + PortName proxy_target_port_name; +}; + +struct ObserveProxyAckEventData { + uint64_t last_sequence_num; +}; + +struct ObserveClosureEventData { + uint64_t last_sequence_num; +}; + +struct MergePortEventData { + PortName new_port_name; + Event::PortDescriptor new_port_descriptor; +}; + +#pragma pack(pop) + +static_assert(sizeof(Event::PortDescriptor) % kPortsMessageAlignment == 0, "Invalid PortDescriptor size."); -static_assert(sizeof(EventHeader) % kPortsMessageAlignment == 0, - "Invalid EventHeader size."); +static_assert(sizeof(SerializedHeader) % kPortsMessageAlignment == 0, + "Invalid SerializedHeader size."); -static_assert(sizeof(UserEventData) % kPortsMessageAlignment == 0, +static_assert(sizeof(UserMessageEventData) % kPortsMessageAlignment == 0, "Invalid UserEventData size."); static_assert(sizeof(ObserveProxyEventData) % kPortsMessageAlignment == 0, @@ -37,10 +77,296 @@ } // namespace -PortDescriptor::PortDescriptor() { +Event::PortDescriptor::PortDescriptor() { memset(padding, 0, sizeof(padding)); } +Event::~Event() = default; + +// static +ScopedEvent Event::Deserialize(const void* buffer, size_t num_bytes) { + if (num_bytes < sizeof(SerializedHeader)) + return nullptr; + + const auto* header = static_cast<const SerializedHeader*>(buffer); + const PortName& port_name = header->port_name; + const size_t data_size = num_bytes - sizeof(header); + switch (header->type) { + case Type::kUserMessage: + return UserMessageEvent::Deserialize(port_name, header + 1, data_size); + case Type::kPortAccepted: + return PortAcceptedEvent::Deserialize(port_name, header + 1, data_size); + case Type::kObserveProxy: + return ObserveProxyEvent::Deserialize(port_name, header + 1, data_size); + case Type::kObserveProxyAck: + return ObserveProxyAckEvent::Deserialize(port_name, header + 1, + data_size); + case Type::kObserveClosure: + return ObserveClosureEvent::Deserialize(port_name, header + 1, data_size); + case Type::kMergePort: + return MergePortEvent::Deserialize(port_name, header + 1, data_size); + default: + DVLOG(2) << "Ingoring unknown port event type: " + << static_cast<uint32_t>(header->type); + return nullptr; + } +} + +Event::Event(Type type, const PortName& port_name) + : type_(type), port_name_(port_name) {} + +size_t Event::GetSerializedSize() const { + return sizeof(SerializedHeader) + GetSerializedDataSize(); +} + +void Event::Serialize(void* buffer) const { + auto* header = static_cast<SerializedHeader*>(buffer); + header->type = type_; + header->padding = 0; + header->port_name = port_name_; + SerializeData(header + 1); +} + +ScopedEvent Event::Clone() const { + return nullptr; +} + +UserMessageEvent::~UserMessageEvent() = default; + +UserMessageEvent::UserMessageEvent(size_t num_ports) + : Event(Type::kUserMessage, kInvalidPortName) { + ReservePorts(num_ports); +} + +void UserMessageEvent::AttachMessage(std::unique_ptr<UserMessage> message) { + DCHECK(!message_); + message_ = std::move(message); +} + +void UserMessageEvent::ReservePorts(size_t num_ports) { + port_descriptors_.resize(num_ports); + ports_.resize(num_ports); +} + +// static +ScopedEvent UserMessageEvent::Deserialize(const PortName& port_name, + const void* buffer, + size_t num_bytes) { + if (num_bytes < sizeof(UserMessageEventData)) + return nullptr; + + const auto* data = static_cast<const UserMessageEventData*>(buffer); + base::CheckedNumeric<size_t> port_data_size = data->num_ports; + port_data_size *= sizeof(PortDescriptor) + sizeof(PortName); + if (!port_data_size.IsValid()) + return nullptr; + + base::CheckedNumeric<size_t> total_size = port_data_size.ValueOrDie(); + total_size += sizeof(UserMessageEventData); + if (!total_size.IsValid() || num_bytes < total_size.ValueOrDie()) + return nullptr; + + auto event = + base::WrapUnique(new UserMessageEvent(port_name, data->sequence_num)); + event->ReservePorts(data->num_ports); + const auto* in_descriptors = + reinterpret_cast<const PortDescriptor*>(data + 1); + std::copy(in_descriptors, in_descriptors + data->num_ports, + event->port_descriptors()); + + const auto* in_names = + reinterpret_cast<const PortName*>(in_descriptors + data->num_ports); + std::copy(in_names, in_names + data->num_ports, event->ports()); + return std::move(event); +} + +UserMessageEvent::UserMessageEvent(const PortName& port_name, + uint64_t sequence_num) + : Event(Type::kUserMessage, port_name), sequence_num_(sequence_num) {} + +size_t UserMessageEvent::GetSerializedDataSize() const { + DCHECK_EQ(ports_.size(), port_descriptors_.size()); + base::CheckedNumeric<size_t> size = sizeof(UserMessageEventData); + base::CheckedNumeric<size_t> ports_size = + sizeof(PortDescriptor) + sizeof(PortName); + ports_size *= ports_.size(); + return (size + ports_size.ValueOrDie()).ValueOrDie(); +} + +void UserMessageEvent::SerializeData(void* buffer) const { + DCHECK_EQ(ports_.size(), port_descriptors_.size()); + auto* data = static_cast<UserMessageEventData*>(buffer); + data->sequence_num = sequence_num_; + DCHECK(base::IsValueInRangeForNumericType<uint32_t>(ports_.size())); + data->num_ports = static_cast<uint32_t>(ports_.size()); + data->padding = 0; + + auto* ports_data = reinterpret_cast<PortDescriptor*>(data + 1); + std::copy(port_descriptors_.begin(), port_descriptors_.end(), ports_data); + + auto* port_names_data = + reinterpret_cast<PortName*>(ports_data + ports_.size()); + std::copy(ports_.begin(), ports_.end(), port_names_data); +} + +PortAcceptedEvent::PortAcceptedEvent(const PortName& port_name) + : Event(Type::kPortAccepted, port_name) {} + +PortAcceptedEvent::~PortAcceptedEvent() = default; + +// static +ScopedEvent PortAcceptedEvent::Deserialize(const PortName& port_name, + const void* buffer, + size_t num_bytes) { + return base::MakeUnique<PortAcceptedEvent>(port_name); +} + +size_t PortAcceptedEvent::GetSerializedDataSize() const { + return 0; +} + +void PortAcceptedEvent::SerializeData(void* buffer) const {} + +ObserveProxyEvent::ObserveProxyEvent(const PortName& port_name, + const NodeName& proxy_node_name, + const PortName& proxy_port_name, + const NodeName& proxy_target_node_name, + const PortName& proxy_target_port_name) + : Event(Type::kObserveProxy, port_name), + proxy_node_name_(proxy_node_name), + proxy_port_name_(proxy_port_name), + proxy_target_node_name_(proxy_target_node_name), + proxy_target_port_name_(proxy_target_port_name) {} + +ObserveProxyEvent::~ObserveProxyEvent() = default; + +// static +ScopedEvent ObserveProxyEvent::Deserialize(const PortName& port_name, + const void* buffer, + size_t num_bytes) { + if (num_bytes < sizeof(ObserveProxyEventData)) + return nullptr; + + const auto* data = static_cast<const ObserveProxyEventData*>(buffer); + return base::MakeUnique<ObserveProxyEvent>( + port_name, data->proxy_node_name, data->proxy_port_name, + data->proxy_target_node_name, data->proxy_target_port_name); +} + +size_t ObserveProxyEvent::GetSerializedDataSize() const { + return sizeof(ObserveProxyEventData); +} + +void ObserveProxyEvent::SerializeData(void* buffer) const { + auto* data = static_cast<ObserveProxyEventData*>(buffer); + data->proxy_node_name = proxy_node_name_; + data->proxy_port_name = proxy_port_name_; + data->proxy_target_node_name = proxy_target_node_name_; + data->proxy_target_port_name = proxy_target_port_name_; +} + +ScopedEvent ObserveProxyEvent::Clone() const { + return base::MakeUnique<ObserveProxyEvent>( + port_name(), proxy_node_name_, proxy_port_name_, proxy_target_node_name_, + proxy_target_port_name_); +} + +ObserveProxyAckEvent::ObserveProxyAckEvent(const PortName& port_name, + uint64_t last_sequence_num) + : Event(Type::kObserveProxyAck, port_name), + last_sequence_num_(last_sequence_num) {} + +ObserveProxyAckEvent::~ObserveProxyAckEvent() = default; + +// static +ScopedEvent ObserveProxyAckEvent::Deserialize(const PortName& port_name, + const void* buffer, + size_t num_bytes) { + if (num_bytes < sizeof(ObserveProxyAckEventData)) + return nullptr; + + const auto* data = static_cast<const ObserveProxyAckEventData*>(buffer); + return base::MakeUnique<ObserveProxyAckEvent>(port_name, + data->last_sequence_num); +} + +size_t ObserveProxyAckEvent::GetSerializedDataSize() const { + return sizeof(ObserveProxyAckEventData); +} + +void ObserveProxyAckEvent::SerializeData(void* buffer) const { + auto* data = static_cast<ObserveProxyAckEventData*>(buffer); + data->last_sequence_num = last_sequence_num_; +} + +ScopedEvent ObserveProxyAckEvent::Clone() const { + return base::MakeUnique<ObserveProxyAckEvent>(port_name(), + last_sequence_num_); +} + +ObserveClosureEvent::ObserveClosureEvent(const PortName& port_name, + uint64_t last_sequence_num) + : Event(Type::kObserveClosure, port_name), + last_sequence_num_(last_sequence_num) {} + +ObserveClosureEvent::~ObserveClosureEvent() = default; + +// static +ScopedEvent ObserveClosureEvent::Deserialize(const PortName& port_name, + const void* buffer, + size_t num_bytes) { + if (num_bytes < sizeof(ObserveClosureEventData)) + return nullptr; + + const auto* data = static_cast<const ObserveClosureEventData*>(buffer); + return base::MakeUnique<ObserveClosureEvent>(port_name, + data->last_sequence_num); +} + +size_t ObserveClosureEvent::GetSerializedDataSize() const { + return sizeof(ObserveClosureEventData); +} + +void ObserveClosureEvent::SerializeData(void* buffer) const { + auto* data = static_cast<ObserveClosureEventData*>(buffer); + data->last_sequence_num = last_sequence_num_; +} + +ScopedEvent ObserveClosureEvent::Clone() const { + return base::MakeUnique<ObserveClosureEvent>(port_name(), last_sequence_num_); +} + +MergePortEvent::MergePortEvent(const PortName& port_name, + const PortName& new_port_name, + const PortDescriptor& new_port_descriptor) + : Event(Type::kMergePort, port_name), + new_port_name_(new_port_name), + new_port_descriptor_(new_port_descriptor) {} + +MergePortEvent::~MergePortEvent() = default; + +// static +ScopedEvent MergePortEvent::Deserialize(const PortName& port_name, + const void* buffer, + size_t num_bytes) { + if (num_bytes < sizeof(MergePortEventData)) + return nullptr; + + const auto* data = static_cast<const MergePortEventData*>(buffer); + return base::MakeUnique<MergePortEvent>(port_name, data->new_port_name, + data->new_port_descriptor); +} + +size_t MergePortEvent::GetSerializedDataSize() const { + return sizeof(MergePortEventData); +} + +void MergePortEvent::SerializeData(void* buffer) const { + auto* data = static_cast<MergePortEventData*>(buffer); + data->new_port_name = new_port_name_; + data->new_port_descriptor = new_port_descriptor_; +} + } // namespace ports } // namespace edk } // namespace mojo
diff --git a/mojo/edk/system/ports/event.h b/mojo/edk/system/ports/event.h index a66dfc1..3e2871c 100644 --- a/mojo/edk/system/ports/event.h +++ b/mojo/edk/system/ports/event.h
@@ -7,102 +7,247 @@ #include <stdint.h> -#include "mojo/edk/system/ports/message.h" +#include <vector> + +#include "base/macros.h" +#include "base/memory/ptr_util.h" #include "mojo/edk/system/ports/name.h" +#include "mojo/edk/system/ports/user_message.h" namespace mojo { namespace edk { namespace ports { +class Event; + +using ScopedEvent = std::unique_ptr<Event>; + +class Event { + public: + enum Type : uint32_t { + kUserMessage, + kPortAccepted, + kObserveProxy, + kObserveProxyAck, + kObserveClosure, + kMergePort, + }; + #pragma pack(push, 1) + struct PortDescriptor { + PortDescriptor(); -// TODO: Add static assertions of alignment. - -struct PortDescriptor { - PortDescriptor(); - - NodeName peer_node_name; - PortName peer_port_name; - NodeName referring_node_name; - PortName referring_port_name; - uint64_t next_sequence_num_to_send; - uint64_t next_sequence_num_to_receive; - uint64_t last_sequence_num_to_receive; - bool peer_closed; - char padding[7]; -}; - -enum struct EventType : uint32_t { - kUser, - kPortAccepted, - kObserveProxy, - kObserveProxyAck, - kObserveClosure, - kMergePort, -}; - -struct EventHeader { - EventType type; - uint32_t padding; - PortName port_name; -}; - -struct UserEventData { - uint64_t sequence_num; - uint32_t num_ports; - uint32_t padding; -}; - -struct ObserveProxyEventData { - NodeName proxy_node_name; - PortName proxy_port_name; - NodeName proxy_to_node_name; - PortName proxy_to_port_name; -}; - -struct ObserveProxyAckEventData { - uint64_t last_sequence_num; -}; - -struct ObserveClosureEventData { - uint64_t last_sequence_num; -}; - -struct MergePortEventData { - PortName new_port_name; - PortDescriptor new_port_descriptor; -}; - + NodeName peer_node_name; + PortName peer_port_name; + NodeName referring_node_name; + PortName referring_port_name; + uint64_t next_sequence_num_to_send; + uint64_t next_sequence_num_to_receive; + uint64_t last_sequence_num_to_receive; + bool peer_closed; + char padding[7]; + }; #pragma pack(pop) + virtual ~Event(); -inline const EventHeader* GetEventHeader(const Message& message) { - return static_cast<const EventHeader*>(message.header_bytes()); -} + static ScopedEvent Deserialize(const void* buffer, size_t num_bytes); -inline EventHeader* GetMutableEventHeader(Message* message) { - return static_cast<EventHeader*>(message->mutable_header_bytes()); -} + template <typename T> + static std::unique_ptr<T> Cast(ScopedEvent* event) { + return base::WrapUnique(static_cast<T*>(event->release())); + } -template <typename EventData> -inline const EventData* GetEventData(const Message& message) { - return reinterpret_cast<const EventData*>( - reinterpret_cast<const char*>(GetEventHeader(message) + 1)); -} + Type type() const { return type_; } + const PortName& port_name() const { return port_name_; } + void set_port_name(const PortName& port_name) { port_name_ = port_name; } -template <typename EventData> -inline EventData* GetMutableEventData(Message* message) { - return reinterpret_cast<EventData*>( - reinterpret_cast<char*>(GetMutableEventHeader(message) + 1)); -} + size_t GetSerializedSize() const; + void Serialize(void* buffer) const; + virtual ScopedEvent Clone() const; -inline const PortDescriptor* GetPortDescriptors(const UserEventData* event) { - return reinterpret_cast<const PortDescriptor*>( - reinterpret_cast<const char*>(event + 1)); -} + protected: + Event(Type type, const PortName& port_name); -inline PortDescriptor* GetMutablePortDescriptors(UserEventData* event) { - return reinterpret_cast<PortDescriptor*>(reinterpret_cast<char*>(event + 1)); -} + virtual size_t GetSerializedDataSize() const = 0; + virtual void SerializeData(void* buffer) const = 0; + + private: + const Type type_; + PortName port_name_; + + DISALLOW_COPY_AND_ASSIGN(Event); +}; + +class UserMessageEvent : public Event { + public: + explicit UserMessageEvent(size_t num_ports); + ~UserMessageEvent() override; + + bool HasMessage() const { return !!message_; } + void AttachMessage(std::unique_ptr<UserMessage> message); + + template <typename T> + T* GetMessage() { + DCHECK(HasMessage()); + DCHECK_EQ(&T::kUserMessageTypeInfo, message_->type_info()); + return static_cast<T*>(message_.get()); + } + + template <typename T> + const T* GetMessage() const { + DCHECK(HasMessage()); + DCHECK_EQ(&T::kUserMessageTypeInfo, message_->type_info()); + return static_cast<const T*>(message_.get()); + } + + void ReservePorts(size_t num_ports); + + uint32_t sequence_num() const { return sequence_num_; } + void set_sequence_num(uint32_t sequence_num) { sequence_num_ = sequence_num; } + + size_t num_ports() const { return ports_.size(); } + PortDescriptor* port_descriptors() { return port_descriptors_.data(); } + PortName* ports() { return ports_.data(); } + + static ScopedEvent Deserialize(const PortName& port_name, + const void* buffer, + size_t num_bytes); + + private: + UserMessageEvent(const PortName& port_name, uint64_t sequence_num); + + size_t GetSerializedDataSize() const override; + void SerializeData(void* buffer) const override; + + uint64_t sequence_num_ = 0; + std::vector<PortDescriptor> port_descriptors_; + std::vector<PortName> ports_; + std::unique_ptr<UserMessage> message_; + + DISALLOW_COPY_AND_ASSIGN(UserMessageEvent); +}; + +class PortAcceptedEvent : public Event { + public: + explicit PortAcceptedEvent(const PortName& port_name); + ~PortAcceptedEvent() override; + + static ScopedEvent Deserialize(const PortName& port_name, + const void* buffer, + size_t num_bytes); + + private: + size_t GetSerializedDataSize() const override; + void SerializeData(void* buffer) const override; + + DISALLOW_COPY_AND_ASSIGN(PortAcceptedEvent); +}; + +class ObserveProxyEvent : public Event { + public: + ObserveProxyEvent(const PortName& port_name, + const NodeName& proxy_node_name, + const PortName& proxy_port_name, + const NodeName& proxy_target_node_name, + const PortName& proxy_target_port_name); + ~ObserveProxyEvent() override; + + const NodeName& proxy_node_name() const { return proxy_node_name_; } + const PortName& proxy_port_name() const { return proxy_port_name_; } + const NodeName& proxy_target_node_name() const { + return proxy_target_node_name_; + } + const PortName& proxy_target_port_name() const { + return proxy_target_port_name_; + } + + static ScopedEvent Deserialize(const PortName& port_name, + const void* buffer, + size_t num_bytes); + + private: + size_t GetSerializedDataSize() const override; + void SerializeData(void* buffer) const override; + ScopedEvent Clone() const override; + + const NodeName proxy_node_name_; + const PortName proxy_port_name_; + const NodeName proxy_target_node_name_; + const PortName proxy_target_port_name_; + + DISALLOW_COPY_AND_ASSIGN(ObserveProxyEvent); +}; + +class ObserveProxyAckEvent : public Event { + public: + ObserveProxyAckEvent(const PortName& port_name, uint64_t last_sequence_num); + ~ObserveProxyAckEvent() override; + + uint64_t last_sequence_num() const { return last_sequence_num_; } + + static ScopedEvent Deserialize(const PortName& port_name, + const void* buffer, + size_t num_bytes); + + private: + size_t GetSerializedDataSize() const override; + void SerializeData(void* buffer) const override; + ScopedEvent Clone() const override; + + const uint64_t last_sequence_num_; + + DISALLOW_COPY_AND_ASSIGN(ObserveProxyAckEvent); +}; + +class ObserveClosureEvent : public Event { + public: + ObserveClosureEvent(const PortName& port_name, uint64_t last_sequence_num); + ~ObserveClosureEvent() override; + + uint64_t last_sequence_num() const { return last_sequence_num_; } + void set_last_sequence_num(uint64_t last_sequence_num) { + last_sequence_num_ = last_sequence_num; + } + + static ScopedEvent Deserialize(const PortName& port_name, + const void* buffer, + size_t num_bytes); + + private: + size_t GetSerializedDataSize() const override; + void SerializeData(void* buffer) const override; + ScopedEvent Clone() const override; + + uint64_t last_sequence_num_; + + DISALLOW_COPY_AND_ASSIGN(ObserveClosureEvent); +}; + +class MergePortEvent : public Event { + public: + MergePortEvent(const PortName& port_name, + const PortName& new_port_name, + const PortDescriptor& new_port_descriptor); + ~MergePortEvent() override; + + const PortName& new_port_name() const { return new_port_name_; } + const PortDescriptor& new_port_descriptor() const { + return new_port_descriptor_; + } + + static ScopedEvent Deserialize(const PortName& port_name, + const void* buffer, + size_t num_bytes); + + private: + size_t GetSerializedDataSize() const override; + void SerializeData(void* buffer) const override; + + const PortName new_port_name_; + const PortDescriptor new_port_descriptor_; + + DISALLOW_COPY_AND_ASSIGN(MergePortEvent); +}; } // namespace ports } // namespace edk
diff --git a/mojo/edk/system/ports/message.cc b/mojo/edk/system/ports/message.cc deleted file mode 100644 index 5d3c000..0000000 --- a/mojo/edk/system/ports/message.cc +++ /dev/null
@@ -1,100 +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 <stdlib.h> - -#include <limits> - -#include "base/logging.h" -#include "mojo/edk/system/ports/event.h" - -namespace mojo { -namespace edk { -namespace ports { - -// static -bool Message::Parse(const void* bytes, - size_t num_bytes, - size_t* num_header_bytes, - size_t* num_payload_bytes, - size_t* num_ports_bytes) { - if (num_bytes < sizeof(EventHeader)) - return false; - const EventHeader* header = static_cast<const EventHeader*>(bytes); - switch (header->type) { - case EventType::kUser: - // See below. - break; - case EventType::kPortAccepted: - *num_header_bytes = sizeof(EventHeader); - break; - case EventType::kObserveProxy: - *num_header_bytes = sizeof(EventHeader) + sizeof(ObserveProxyEventData); - break; - case EventType::kObserveProxyAck: - *num_header_bytes = - sizeof(EventHeader) + sizeof(ObserveProxyAckEventData); - break; - case EventType::kObserveClosure: - *num_header_bytes = sizeof(EventHeader) + sizeof(ObserveClosureEventData); - break; - case EventType::kMergePort: - *num_header_bytes = sizeof(EventHeader) + sizeof(MergePortEventData); - break; - default: - return false; - } - - if (header->type == EventType::kUser) { - if (num_bytes < sizeof(EventHeader) + sizeof(UserEventData)) - return false; - const UserEventData* event_data = - reinterpret_cast<const UserEventData*>( - reinterpret_cast<const char*>(header + 1)); - if (event_data->num_ports > std::numeric_limits<uint16_t>::max()) - return false; - *num_header_bytes = sizeof(EventHeader) + - sizeof(UserEventData) + - event_data->num_ports * sizeof(PortDescriptor); - *num_ports_bytes = event_data->num_ports * sizeof(PortName); - if (num_bytes < *num_header_bytes + *num_ports_bytes) - return false; - *num_payload_bytes = num_bytes - *num_header_bytes - *num_ports_bytes; - } else { - if (*num_header_bytes != num_bytes) - return false; - *num_payload_bytes = 0; - *num_ports_bytes = 0; - } - - return true; -} - -Message::Message(size_t num_payload_bytes, size_t num_ports) - : Message(sizeof(EventHeader) + sizeof(UserEventData) + - num_ports * sizeof(PortDescriptor), - num_payload_bytes, num_ports * sizeof(PortName)) { - num_ports_ = num_ports; -} - -Message::Message(size_t num_header_bytes, - size_t num_payload_bytes, - size_t num_ports_bytes) - : start_(nullptr), - num_header_bytes_(num_header_bytes), - num_ports_bytes_(num_ports_bytes), - num_payload_bytes_(num_payload_bytes) { -} - -void Message::InitializeUserMessageHeader(void* start) { - start_ = static_cast<char*>(start); - memset(start_, 0, num_header_bytes_); - GetMutableEventHeader(this)->type = EventType::kUser; - GetMutableEventData<UserEventData>(this)->num_ports = - static_cast<uint32_t>(num_ports_); -} - -} // namespace ports -} // namespace edk -} // namespace mojo
diff --git a/mojo/edk/system/ports/message.h b/mojo/edk/system/ports/message.h deleted file mode 100644 index 95fa046..0000000 --- a/mojo/edk/system/ports/message.h +++ /dev/null
@@ -1,93 +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 MOJO_EDK_SYSTEM_PORTS_MESSAGE_H_ -#define MOJO_EDK_SYSTEM_PORTS_MESSAGE_H_ - -#include <stddef.h> - -#include <memory> - -#include "mojo/edk/system/ports/name.h" - -namespace mojo { -namespace edk { -namespace ports { - -// A message consists of a header (array of bytes), payload (array of bytes) -// and an array of ports. The header is used by the Node implementation. -// -// This class is designed to be subclassed, and the subclass is responsible for -// providing the underlying storage. The header size will be aligned, and it -// should be followed in memory by the array of ports and finally the payload. -// -// NOTE: This class does not manage the lifetime of the ports it references. -class Message { - public: - virtual ~Message() {} - - // Inspect the message at |bytes| and return the size of each section. Returns - // |false| if the message is malformed and |true| otherwise. - static bool Parse(const void* bytes, - size_t num_bytes, - size_t* num_header_bytes, - size_t* num_payload_bytes, - size_t* num_ports_bytes); - - void* mutable_header_bytes() { return start_; } - const void* header_bytes() const { return start_; } - size_t num_header_bytes() const { return num_header_bytes_; } - - void* mutable_payload_bytes() { - return start_ + num_header_bytes_ + num_ports_bytes_; - } - const void* payload_bytes() const { - return const_cast<Message*>(this)->mutable_payload_bytes(); - } - size_t num_payload_bytes() const { return num_payload_bytes_; } - - PortName* mutable_ports() { - return reinterpret_cast<PortName*>(start_ + num_header_bytes_); - } - const PortName* ports() const { - return const_cast<Message*>(this)->mutable_ports(); - } - size_t num_ports_bytes() const { return num_ports_bytes_; } - size_t num_ports() const { return num_ports_bytes_ / sizeof(PortName); } - - protected: - // Constructs a new Message base for a user message. - // - // Note: You MUST call InitializeUserMessageHeader() before this Message is - // ready for transmission. - Message(size_t num_payload_bytes, size_t num_ports); - - // Constructs a new Message base for an internal message. Do NOT call - // InitializeUserMessageHeader() when using this constructor. - Message(size_t num_header_bytes, - size_t num_payload_bytes, - size_t num_ports_bytes); - - Message(const Message& other) = delete; - void operator=(const Message& other) = delete; - - // Initializes the header in a newly allocated message buffer to carry a - // user message. - void InitializeUserMessageHeader(void* start); - - // Note: storage is [header][ports][payload]. - char* start_ = nullptr; - size_t num_ports_ = 0; - size_t num_header_bytes_ = 0; - size_t num_ports_bytes_ = 0; - size_t num_payload_bytes_ = 0; -}; - -using ScopedMessage = std::unique_ptr<Message>; - -} // namespace ports -} // namespace edk -} // namespace mojo - -#endif // MOJO_EDK_SYSTEM_PORTS_MESSAGE_H_
diff --git a/mojo/edk/system/ports/message_filter.h b/mojo/edk/system/ports/message_filter.h index bf8fa21..1b1f2ce 100644 --- a/mojo/edk/system/ports/message_filter.h +++ b/mojo/edk/system/ports/message_filter.h
@@ -9,17 +9,17 @@ namespace edk { namespace ports { -class Message; +class UserMessageEvent; -// An interface which can be implemented to filter port messages according to +// An interface which can be implemented to user message events according to // arbitrary policy. class MessageFilter { public: virtual ~MessageFilter() {} - // Returns true of |message| should be accepted by whomever is applying this + // Returns true if |message| should be accepted by whomever is applying this // filter. See MessageQueue::GetNextMessage(), for example. - virtual bool Match(const Message& message) = 0; + virtual bool Match(const UserMessageEvent& message) = 0; }; } // namespace ports
diff --git a/mojo/edk/system/ports/message_queue.cc b/mojo/edk/system/ports/message_queue.cc index defb1b6..f1a9719 100644 --- a/mojo/edk/system/ports/message_queue.cc +++ b/mojo/edk/system/ports/message_queue.cc
@@ -7,20 +7,16 @@ #include <algorithm> #include "base/logging.h" -#include "mojo/edk/system/ports/event.h" #include "mojo/edk/system/ports/message_filter.h" namespace mojo { namespace edk { namespace ports { -inline uint64_t GetSequenceNum(const ScopedMessage& message) { - return GetEventData<UserEventData>(*message)->sequence_num; -} - // Used by std::{push,pop}_heap functions -inline bool operator<(const ScopedMessage& a, const ScopedMessage& b) { - return GetSequenceNum(a) > GetSequenceNum(b); +inline bool operator<(const std::unique_ptr<UserMessageEvent>& a, + const std::unique_ptr<UserMessageEvent>& b) { + return a->sequence_num() > b->sequence_num(); } MessageQueue::MessageQueue() : MessageQueue(kInitialSequenceNum) {} @@ -42,12 +38,12 @@ } bool MessageQueue::HasNextMessage() const { - return !heap_.empty() && GetSequenceNum(heap_[0]) == next_sequence_num_; + return !heap_.empty() && heap_[0]->sequence_num() == next_sequence_num_; } -void MessageQueue::GetNextMessage(ScopedMessage* message, +void MessageQueue::GetNextMessage(std::unique_ptr<UserMessageEvent>* message, MessageFilter* filter) { - if (!HasNextMessage() || (filter && !filter->Match(*heap_[0].get()))) { + if (!HasNextMessage() || (filter && !filter->Match(*heap_[0]))) { message->reset(); return; } @@ -59,10 +55,8 @@ next_sequence_num_++; } -void MessageQueue::AcceptMessage(ScopedMessage message, +void MessageQueue::AcceptMessage(std::unique_ptr<UserMessageEvent> message, bool* has_next_message) { - DCHECK(GetEventHeader(*message)->type == EventType::kUser); - // TODO: Handle sequence number roll-over. heap_.emplace_back(std::move(message)); @@ -71,7 +65,7 @@ if (!signalable_) { *has_next_message = false; } else { - *has_next_message = (GetSequenceNum(heap_[0]) == next_sequence_num_); + *has_next_message = (heap_[0]->sequence_num() == next_sequence_num_); } }
diff --git a/mojo/edk/system/ports/message_queue.h b/mojo/edk/system/ports/message_queue.h index d9a47ed..8ff3ab9 100644 --- a/mojo/edk/system/ports/message_queue.h +++ b/mojo/edk/system/ports/message_queue.h
@@ -8,12 +8,12 @@ #include <stdint.h> #include <deque> -#include <functional> #include <limits> +#include <memory> #include <vector> #include "base/macros.h" -#include "mojo/edk/system/ports/message.h" +#include "mojo/edk/system/ports/event.h" namespace mojo { namespace edk { @@ -42,7 +42,8 @@ // Gives ownership of the message. If |filter| is non-null, the next message // will only be retrieved if the filter successfully matches it. - void GetNextMessage(ScopedMessage* message, MessageFilter* filter); + void GetNextMessage(std::unique_ptr<UserMessageEvent>* message, + MessageFilter* filter); // Takes ownership of the message. Note: Messages are ordered, so while we // have added a message to the queue, we may still be waiting on a message @@ -53,13 +54,14 @@ // until GetNextMessage is called enough times to return a null message. // In other words, has_next_message acts like an edge trigger. // - void AcceptMessage(ScopedMessage message, bool* has_next_message); + void AcceptMessage(std::unique_ptr<UserMessageEvent> message, + bool* has_next_message); // Returns all of the ports referenced by messages in this message queue. void GetReferencedPorts(std::deque<PortName>* ports); private: - std::vector<ScopedMessage> heap_; + std::vector<std::unique_ptr<UserMessageEvent>> heap_; uint64_t next_sequence_num_; bool signalable_ = true;
diff --git a/mojo/edk/system/ports/node.cc b/mojo/edk/system/ports/node.cc index 9c6f1fd9..f6217a7 100644 --- a/mojo/edk/system/ports/node.cc +++ b/mojo/edk/system/ports/node.cc
@@ -12,6 +12,7 @@ #include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/synchronization/lock.h" +#include "mojo/edk/system/ports/event.h" #include "mojo/edk/system/ports/node_delegate.h" namespace mojo { @@ -197,10 +198,9 @@ int Node::ClosePort(const PortRef& port_ref) { std::deque<PortName> referenced_port_names; - ObserveClosureEventData data; - NodeName peer_node_name; PortName peer_port_name; + uint64_t last_sequence_num = 0; Port* port = port_ref.port(); { // We may need to erase the port, which requires ports_lock_ to be held, @@ -222,7 +222,7 @@ // We pass along the sequence number of the last message sent from this // port to allow the peer to have the opportunity to consume all inbound // messages before notifying the embedder that this port is closed. - data.last_sequence_num = port->next_sequence_num_to_send - 1; + last_sequence_num = port->next_sequence_num_to_send - 1; peer_node_name = port->peer_node_name; peer_port_name = port->peer_port_name; @@ -237,9 +237,9 @@ DVLOG(2) << "Sending ObserveClosure from " << port_ref.name() << "@" << name_ << " to " << peer_port_name << "@" << peer_node_name; - delegate_->ForwardMessage( + delegate_->ForwardEvent( peer_node_name, - NewInternalMessage(peer_port_name, EventType::kObserveClosure, data)); + base::MakeUnique<ObserveClosureEvent>(peer_port_name, last_sequence_num)); for (const auto& name : referenced_port_names) { PortRef ref; @@ -264,7 +264,7 @@ } int Node::GetMessage(const PortRef& port_ref, - ScopedMessage* message, + std::unique_ptr<UserMessageEvent>* message, MessageFilter* filter) { *message = nullptr; @@ -306,8 +306,9 @@ return OK; } -int Node::SendMessage(const PortRef& port_ref, ScopedMessage message) { - int rv = SendMessageInternal(port_ref, &message); +int Node::SendUserMessage(const PortRef& port_ref, + std::unique_ptr<UserMessageEvent> message) { + int rv = SendUserMessageInternal(port_ref, &message); if (rv != OK) { // If send failed, close all carried ports. Note that we're careful not to // close the sending port itself if it happened to be one of the encoded @@ -324,28 +325,20 @@ return rv; } -int Node::AcceptMessage(ScopedMessage message) { - const EventHeader* header = GetEventHeader(*message); - switch (header->type) { - case EventType::kUser: - return OnUserMessage(std::move(message)); - case EventType::kPortAccepted: - return OnPortAccepted(header->port_name); - case EventType::kObserveProxy: - return OnObserveProxy( - header->port_name, - *GetEventData<ObserveProxyEventData>(*message)); - case EventType::kObserveProxyAck: - return OnObserveProxyAck( - header->port_name, - GetEventData<ObserveProxyAckEventData>(*message)->last_sequence_num); - case EventType::kObserveClosure: - return OnObserveClosure( - header->port_name, - GetEventData<ObserveClosureEventData>(*message)->last_sequence_num); - case EventType::kMergePort: - return OnMergePort(header->port_name, - *GetEventData<MergePortEventData>(*message)); +int Node::AcceptEvent(ScopedEvent event) { + switch (event->type()) { + case Event::Type::kUserMessage: + return OnUserMessage(Event::Cast<UserMessageEvent>(&event)); + case Event::Type::kPortAccepted: + return OnPortAccepted(Event::Cast<PortAcceptedEvent>(&event)); + case Event::Type::kObserveProxy: + return OnObserveProxy(Event::Cast<ObserveProxyEvent>(&event)); + case Event::Type::kObserveProxyAck: + return OnObserveProxyAck(Event::Cast<ObserveProxyAckEvent>(&event)); + case Event::Type::kObserveClosure: + return OnObserveClosure(Event::Cast<ObserveClosureEvent>(&event)); + case Event::Type::kMergePort: + return OnMergePort(Event::Cast<MergePortEvent>(&event)); } return OOPS(ERROR_NOT_IMPLEMENTED); } @@ -354,7 +347,8 @@ const NodeName& destination_node_name, const PortName& destination_port_name) { Port* port = port_ref.port(); - MergePortEventData data; + PortName new_port_name; + Event::PortDescriptor new_port_descriptor; { base::AutoLock lock(port->lock); @@ -363,14 +357,14 @@ // Send the port-to-merge over to the destination node so it can be merged // into the port cycle atomically there. - data.new_port_name = port_ref.name(); - WillSendPort(LockedPort(port), destination_node_name, &data.new_port_name, - &data.new_port_descriptor); + new_port_name = port_ref.name(); + WillSendPort(LockedPort(port), destination_node_name, &new_port_name, + &new_port_descriptor); } - delegate_->ForwardMessage( + delegate_->ForwardEvent( destination_node_name, - NewInternalMessage(destination_port_name, - EventType::kMergePort, data)); + base::MakeUnique<MergePortEvent>(destination_port_name, new_port_name, + new_port_descriptor)); return OK; } @@ -412,9 +406,8 @@ return OK; } -int Node::OnUserMessage(ScopedMessage message) { - PortName port_name = GetEventHeader(*message)->port_name; - const auto* event = GetEventData<UserEventData>(*message); +int Node::OnUserMessage(std::unique_ptr<UserMessageEvent> message) { + PortName port_name = message->port_name(); #if DCHECK_IS_ON() std::ostringstream ports_buf; @@ -424,9 +417,9 @@ ports_buf << message->ports()[i]; } - DVLOG(4) << "AcceptMessage " << event->sequence_num - << " [ports=" << ports_buf.str() << "] at " - << port_name << "@" << name_; + DVLOG(4) << "OnUserMessage " << message->sequence_num() + << " [ports=" << ports_buf.str() << "] at " << port_name << "@" + << name_; #endif scoped_refptr<Port> port = GetPort(port_name); @@ -438,7 +431,7 @@ // newly bound ports will simply be closed. for (size_t i = 0; i < message->num_ports(); ++i) { - int rv = AcceptPort(message->ports()[i], GetPortDescriptors(event)[i]); + int rv = AcceptPort(message->ports()[i], message->port_descriptors()[i]); if (rv != OK) return rv; } @@ -495,20 +488,20 @@ return OK; } -int Node::OnPortAccepted(const PortName& port_name) { +int Node::OnPortAccepted(std::unique_ptr<PortAcceptedEvent> event) { + const PortName& port_name = event->port_name(); scoped_refptr<Port> port = GetPort(port_name); if (!port) return ERROR_PORT_UNKNOWN; - DVLOG(2) << "PortAccepted at " << port_name << "@" << name_ - << " pointing to " + DVLOG(2) << "PortAccepted at " << port_name << "@" << name_ << " pointing to " << port->peer_port_name << "@" << port->peer_node_name; return BeginProxying(PortRef(port_name, std::move(port))); } -int Node::OnObserveProxy(const PortName& port_name, - const ObserveProxyEventData& event) { +int Node::OnObserveProxy(std::unique_ptr<ObserveProxyEvent> event) { + const PortName& port_name = event->port_name(); if (port_name == kInvalidPortName) { // An ObserveProxy with an invalid target port name is a broadcast used to // inform ports when their peer (which was itself a proxy) has become @@ -517,9 +510,9 @@ // Receiving ports affected by this treat it as equivalent to peer closure. // Proxies affected by this can be removed and will in turn broadcast their // own death with a similar message. - CHECK_EQ(event.proxy_to_node_name, kInvalidNodeName); - CHECK_EQ(event.proxy_to_port_name, kInvalidPortName); - DestroyAllPortsWithPeer(event.proxy_node_name, event.proxy_port_name); + DCHECK_EQ(event->proxy_target_node_name(), kInvalidNodeName); + DCHECK_EQ(event->proxy_target_port_name(), kInvalidPortName); + DestroyAllPortsWithPeer(event->proxy_node_name(), event->proxy_port_name()); return OK; } @@ -533,28 +526,22 @@ } DVLOG(2) << "ObserveProxy at " << port_name << "@" << name_ << ", proxy at " - << event.proxy_port_name << "@" - << event.proxy_node_name << " pointing to " - << event.proxy_to_port_name << "@" - << event.proxy_to_node_name; + << event->proxy_port_name() << "@" << event->proxy_node_name() + << " pointing to " << event->proxy_target_port_name() << "@" + << event->proxy_target_node_name(); { base::AutoLock lock(port->lock); - if (port->peer_node_name == event.proxy_node_name && - port->peer_port_name == event.proxy_port_name) { + if (port->peer_node_name == event->proxy_node_name() && + port->peer_port_name == event->proxy_port_name()) { if (port->state == Port::kReceiving) { - port->peer_node_name = event.proxy_to_node_name; - port->peer_port_name = event.proxy_to_port_name; - - ObserveProxyAckEventData ack; - ack.last_sequence_num = port->next_sequence_num_to_send - 1; - - delegate_->ForwardMessage( - event.proxy_node_name, - NewInternalMessage(event.proxy_port_name, - EventType::kObserveProxyAck, - ack)); + port->peer_node_name = event->proxy_target_node_name(); + port->peer_port_name = event->proxy_target_port_name(); + delegate_->ForwardEvent( + event->proxy_node_name(), + base::MakeUnique<ObserveProxyAckEvent>( + event->proxy_port_name(), port->next_sequence_num_to_send - 1)); } else { // As a proxy ourselves, we don't know how to honor the ObserveProxy // event or to populate the last_sequence_num field of ObserveProxyAck. @@ -566,36 +553,29 @@ // Otherwise, we might just find ourselves back here again, which // would be akin to a busy loop. - DVLOG(2) << "Delaying ObserveProxyAck to " - << event.proxy_port_name << "@" << event.proxy_node_name; + DVLOG(2) << "Delaying ObserveProxyAck to " << event->proxy_port_name() + << "@" << event->proxy_node_name(); - ObserveProxyAckEventData ack; - ack.last_sequence_num = kInvalidSequenceNum; - - port->send_on_proxy_removal.reset( - new std::pair<NodeName, ScopedMessage>( - event.proxy_node_name, - NewInternalMessage(event.proxy_port_name, - EventType::kObserveProxyAck, - ack))); + port->send_on_proxy_removal.reset(new std::pair<NodeName, ScopedEvent>( + event->proxy_node_name(), + base::MakeUnique<ObserveProxyAckEvent>(event->proxy_port_name(), + kInvalidSequenceNum))); } } else { // Forward this event along to our peer. Eventually, it should find the // port referring to the proxy. - delegate_->ForwardMessage( - port->peer_node_name, - NewInternalMessage(port->peer_port_name, - EventType::kObserveProxy, - event)); + event->set_port_name(port->peer_port_name); + delegate_->ForwardEvent(port->peer_node_name, std::move(event)); } } return OK; } -int Node::OnObserveProxyAck(const PortName& port_name, - uint64_t last_sequence_num) { +int Node::OnObserveProxyAck(std::unique_ptr<ObserveProxyAckEvent> event) { + const PortName& port_name = event->port_name(); + DVLOG(2) << "ObserveProxyAck at " << port_name << "@" << name_ - << " (last_sequence_num=" << last_sequence_num << ")"; + << " (last_sequence_num=" << event->last_sequence_num() << ")"; scoped_refptr<Port> port = GetPort(port_name); if (!port) @@ -608,7 +588,7 @@ if (port->state != Port::kProxying) return OOPS(ERROR_PORT_STATE_UNEXPECTED); - if (last_sequence_num == kInvalidSequenceNum) { + if (event->last_sequence_num() == kInvalidSequenceNum) { // Send again. InitiateProxyRemoval(LockedPort(port.get()), port_name); return OK; @@ -617,14 +597,15 @@ // We can now remove this port once we have received and forwarded the last // message addressed to this port. port->remove_proxy_on_last_message = true; - port->last_sequence_num_to_receive = last_sequence_num; + port->last_sequence_num_to_receive = event->last_sequence_num(); } TryRemoveProxy(PortRef(port_name, std::move(port))); return OK; } -int Node::OnObserveClosure(const PortName& port_name, - uint64_t last_sequence_num) { +int Node::OnObserveClosure(std::unique_ptr<ObserveClosureEvent> event) { + PortName port_name = event->port_name(); + // OK if the port doesn't exist, as it may have been closed already. scoped_refptr<Port> port = GetPort(port_name); if (!port) @@ -636,7 +617,6 @@ // ObserveProxyAck. bool notify_delegate = false; - ObserveClosureEventData forwarded_data; NodeName peer_node_name; PortName peer_port_name; bool try_remove_proxy = false; @@ -644,12 +624,12 @@ base::AutoLock lock(port->lock); port->peer_closed = true; - port->last_sequence_num_to_receive = last_sequence_num; + port->last_sequence_num_to_receive = event->last_sequence_num(); DVLOG(2) << "ObserveClosure at " << port_name << "@" << name_ << " (state=" << port->state << ") pointing to " << port->peer_port_name << "@" << port->peer_node_name - << " (last_sequence_num=" << last_sequence_num << ")"; + << " (last_sequence_num=" << event->last_sequence_num() << ")"; // We always forward ObserveClosure, even beyond the receiving port which // cares about it. This ensures that any dead-end proxies beyond that port @@ -665,12 +645,10 @@ // TODO: Repurposing ObserveClosure for this has the desired result but // may be semantically confusing since the forwarding port is not actually // closed. Consider replacing this with a new event type. - forwarded_data.last_sequence_num = port->next_sequence_num_to_send - 1; + event->set_last_sequence_num(port->next_sequence_num_to_send - 1); } else { - // We haven't yet reached the receiving peer of the closed port, so + // We haven't yet reached the receiving peer of the closed port, so we'll // forward the message along as-is. - forwarded_data.last_sequence_num = last_sequence_num; - // See about removing the port if it is a proxy as our peer won't be able // to participate in proxy removal. port->remove_proxy_on_last_message = true; @@ -678,11 +656,10 @@ try_remove_proxy = true; } - DVLOG(2) << "Forwarding ObserveClosure from " - << port_name << "@" << name_ << " to peer " - << port->peer_port_name << "@" << port->peer_node_name - << " (last_sequence_num=" << forwarded_data.last_sequence_num - << ")"; + DVLOG(2) << "Forwarding ObserveClosure from " << port_name << "@" << name_ + << " to peer " << port->peer_port_name << "@" + << port->peer_node_name + << " (last_sequence_num=" << event->last_sequence_num() << ")"; peer_node_name = port->peer_node_name; peer_port_name = port->peer_port_name; @@ -690,10 +667,8 @@ if (try_remove_proxy) TryRemoveProxy(PortRef(port_name, port)); - delegate_->ForwardMessage( - peer_node_name, - NewInternalMessage(peer_port_name, EventType::kObserveClosure, - forwarded_data)); + event->set_port_name(peer_port_name); + delegate_->ForwardEvent(peer_node_name, std::move(event)); if (notify_delegate) { PortRef port_ref(port_name, std::move(port)); @@ -702,25 +677,24 @@ return OK; } -int Node::OnMergePort(const PortName& port_name, - const MergePortEventData& event) { +int Node::OnMergePort(std::unique_ptr<MergePortEvent> event) { + const PortName& port_name = event->port_name(); scoped_refptr<Port> port = GetPort(port_name); - DVLOG(1) << "MergePort at " << port_name << "@" << name_ << " (state=" - << (port ? port->state : -1) << ") merging with proxy " - << event.new_port_name - << "@" << name_ << " pointing to " - << event.new_port_descriptor.peer_port_name << "@" - << event.new_port_descriptor.peer_node_name << " referred by " - << event.new_port_descriptor.referring_port_name << "@" - << event.new_port_descriptor.referring_node_name; + DVLOG(1) << "MergePort at " << port_name << "@" << name_ + << " (state=" << (port ? port->state : -1) << ") merging with proxy " + << event->new_port_name() << "@" << name_ << " pointing to " + << event->new_port_descriptor().peer_port_name << "@" + << event->new_port_descriptor().peer_node_name << " referred by " + << event->new_port_descriptor().referring_port_name << "@" + << event->new_port_descriptor().referring_node_name; bool close_target_port = false; bool close_new_port = false; // Accept the new port. This is now the receiving end of the other port cycle // to be merged with ours. - int rv = AcceptPort(event.new_port_name, event.new_port_descriptor); + int rv = AcceptPort(event->new_port_name(), event->new_port_descriptor()); if (rv != OK) { close_target_port = true; } else if (port) { @@ -732,7 +706,7 @@ if (port->state != Port::kReceiving) { close_new_port = true; } else { - scoped_refptr<Port> new_port = GetPort_Locked(event.new_port_name); + scoped_refptr<Port> new_port = GetPort_Locked(event->new_port_name()); base::AutoLock new_port_lock(new_port->lock); DCHECK(new_port->state == Port::kReceiving); @@ -740,7 +714,7 @@ // information and set them up as proxies. PortRef port0_ref(port_name, port); - PortRef port1_ref(event.new_port_name, new_port); + PortRef port1_ref(event->new_port_name(), new_port); int rv = MergePorts_Locked(port0_ref, port1_ref); if (rv == OK) return rv; @@ -762,7 +736,7 @@ if (close_new_port) { PortRef new_port; - rv = GetPort(event.new_port_name, &new_port); + rv = GetPort(event->new_port_name(), &new_port); DCHECK(rv == OK); ClosePort(new_port); @@ -811,8 +785,9 @@ return iter->second; } -int Node::SendMessageInternal(const PortRef& port_ref, ScopedMessage* message) { - ScopedMessage& m = *message; +int Node::SendUserMessageInternal(const PortRef& port_ref, + std::unique_ptr<UserMessageEvent>* message) { + std::unique_ptr<UserMessageEvent>& m = *message; for (size_t i = 0; i < m->num_ports(); ++i) { if (m->ports()[i] == port_ref.name()) return ERROR_PORT_CANNOT_SEND_SELF; @@ -822,7 +797,8 @@ NodeName peer_node_name; { // We must acquire |ports_lock_| before grabbing any port locks, because - // WillSendMessage_Locked may need to lock multiple ports out of order. + // WillForwardUserMessage_Locked may need to lock multiple ports out of + // order. base::AutoLock ports_lock(ports_lock_); base::AutoLock lock(port->lock); @@ -832,7 +808,8 @@ if (port->peer_closed) return ERROR_PORT_PEER_CLOSED; - int rv = WillSendMessage_Locked(LockedPort(port), port_ref.name(), m.get()); + int rv = WillForwardUserMessage_Locked(LockedPort(port), port_ref.name(), + m.get()); if (rv != OK) return rv; @@ -845,14 +822,14 @@ } if (peer_node_name != name_) { - delegate_->ForwardMessage(peer_node_name, std::move(m)); + delegate_->ForwardEvent(peer_node_name, std::move(m)); return OK; } - int rv = AcceptMessage(std::move(m)); + int rv = AcceptEvent(std::move(m)); if (rv != OK) { // See comment above for why we don't return an error in this case. - DVLOG(2) << "AcceptMessage failed: " << rv; + DVLOG(2) << "AcceptEvent failed: " << rv; } return OK; @@ -903,21 +880,17 @@ // If either merged port had a closed peer, its new peer needs to be // informed of this. if (port1->peer_closed) { - ObserveClosureEventData data; - data.last_sequence_num = port0->last_sequence_num_to_receive; - delegate_->ForwardMessage( + delegate_->ForwardEvent( port0->peer_node_name, - NewInternalMessage(port0->peer_port_name, - EventType::kObserveClosure, data)); + base::MakeUnique<ObserveClosureEvent>( + port0->peer_port_name, port0->last_sequence_num_to_receive)); } if (port0->peer_closed) { - ObserveClosureEventData data; - data.last_sequence_num = port1->last_sequence_num_to_receive; - delegate_->ForwardMessage( + delegate_->ForwardEvent( port1->peer_node_name, - NewInternalMessage(port1->peer_port_name, - EventType::kObserveClosure, data)); + base::MakeUnique<ObserveClosureEvent>( + port1->peer_port_name, port1->last_sequence_num_to_receive)); } return OK; @@ -940,7 +913,7 @@ void Node::WillSendPort(const LockedPort& port, const NodeName& to_node_name, PortName* port_name, - PortDescriptor* port_descriptor) { + Event::PortDescriptor* port_descriptor) { port->lock.AssertAcquired(); PortName local_port_name = *port_name; @@ -978,7 +951,7 @@ } int Node::AcceptPort(const PortName& port_name, - const PortDescriptor& port_descriptor) { + const Event::PortDescriptor& port_descriptor) { scoped_refptr<Port> port = make_scoped_refptr( new Port(port_descriptor.next_sequence_num_to_send, port_descriptor.next_sequence_num_to_receive)); @@ -1002,16 +975,15 @@ return rv; // Allow referring port to forward messages. - delegate_->ForwardMessage( + delegate_->ForwardEvent( port_descriptor.referring_node_name, - NewInternalMessage(port_descriptor.referring_port_name, - EventType::kPortAccepted)); + base::MakeUnique<PortAcceptedEvent>(port_descriptor.referring_port_name)); return OK; } -int Node::WillSendMessage_Locked(const LockedPort& port, - const PortName& port_name, - Message* message) { +int Node::WillForwardUserMessage_Locked(const LockedPort& port, + const PortName& port_name, + UserMessageEvent* message) { ports_lock_.AssertAcquired(); port->lock.AssertAcquired(); @@ -1019,10 +991,8 @@ // Messages may already have a sequence number if they're being forwarded // by a proxy. Otherwise, use the next outgoing sequence number. - uint64_t* sequence_num = - &GetMutableEventData<UserEventData>(message)->sequence_num; - if (*sequence_num == 0) - *sequence_num = port->next_sequence_num_to_send++; + if (message->sequence_num() == 0) + message->set_sequence_num(port->next_sequence_num_to_send++); #if DCHECK_IS_ON() std::ostringstream ports_buf; @@ -1063,14 +1033,10 @@ } } - PortDescriptor* port_descriptors = - GetMutablePortDescriptors(GetMutableEventData<UserEventData>(message)); - + Event::PortDescriptor* port_descriptors = message->port_descriptors(); for (size_t i = 0; i < message->num_ports(); ++i) { - WillSendPort(LockedPort(ports[i].get()), - port->peer_node_name, - message->mutable_ports() + i, - port_descriptors + i); + WillSendPort(LockedPort(ports[i].get()), port->peer_node_name, + message->ports() + i, port_descriptors + i); } for (size_t i = 0; i < message->num_ports(); ++i) @@ -1078,14 +1044,13 @@ } #if DCHECK_IS_ON() - DVLOG(4) << "Sending message " - << GetEventData<UserEventData>(*message)->sequence_num + DVLOG(4) << "Sending message " << message->sequence_num() << " [ports=" << ports_buf.str() << "]" - << " from " << port_name << "@" << name_ - << " to " << port->peer_port_name << "@" << port->peer_node_name; + << " from " << port_name << "@" << name_ << " to " + << port->peer_port_name << "@" << port->peer_node_name; #endif - GetMutableEventHeader(message)->port_name = port->peer_port_name; + message->set_port_name(port->peer_port_name); return OK; } @@ -1111,12 +1076,10 @@ MaybeRemoveProxy_Locked(LockedPort(port), port_name); // Make sure we propagate closure to our current peer. - ObserveClosureEventData data; - data.last_sequence_num = port->last_sequence_num_to_receive; - delegate_->ForwardMessage( + delegate_->ForwardEvent( port->peer_node_name, - NewInternalMessage(port->peer_port_name, - EventType::kObserveClosure, data)); + base::MakeUnique<ObserveClosureEvent>( + port->peer_port_name, port->last_sequence_num_to_receive)); } else { InitiateProxyRemoval(LockedPort(port), port_name); } @@ -1142,7 +1105,7 @@ bool should_remove; NodeName peer_node_name; - ScopedMessage closure_message; + ScopedEvent closure_event; { base::AutoLock lock(port->lock); if (port->state != Port::kProxying) @@ -1151,11 +1114,9 @@ should_remove = port->remove_proxy_on_last_message; if (should_remove) { // Make sure we propagate closure to our current peer. - ObserveClosureEventData data; - data.last_sequence_num = port->last_sequence_num_to_receive; peer_node_name = port->peer_node_name; - closure_message = NewInternalMessage(port->peer_port_name, - EventType::kObserveClosure, data); + closure_event = base::MakeUnique<ObserveClosureEvent>( + port->peer_port_name, port->last_sequence_num_to_receive); } else { InitiateProxyRemoval(LockedPort(port), port_ref.name()); } @@ -1163,7 +1124,7 @@ if (should_remove) { TryRemoveProxy(port_ref); - delegate_->ForwardMessage(peer_node_name, std::move(closure_message)); + delegate_->ForwardEvent(peer_node_name, std::move(closure_event)); } return OK; @@ -1175,16 +1136,17 @@ port->lock.AssertAcquired(); for (;;) { - ScopedMessage message; + std::unique_ptr<UserMessageEvent> message; port->message_queue.GetNextMessage(&message, nullptr); if (!message) break; - int rv = WillSendMessage_Locked(LockedPort(port), port_name, message.get()); + int rv = WillForwardUserMessage_Locked(LockedPort(port), port_name, + message.get()); if (rv != OK) return rv; - delegate_->ForwardMessage(port->peer_node_name, std::move(message)); + delegate_->ForwardEvent(port->peer_node_name, std::move(message)); } return OK; } @@ -1198,15 +1160,10 @@ // Eventually, this node will receive ObserveProxyAck (or ObserveClosure if // the peer was closed in the meantime). - ObserveProxyEventData data; - data.proxy_node_name = name_; - data.proxy_port_name = port_name; - data.proxy_to_node_name = port->peer_node_name; - data.proxy_to_port_name = port->peer_port_name; - - delegate_->ForwardMessage( - port->peer_node_name, - NewInternalMessage(port->peer_port_name, EventType::kObserveProxy, data)); + delegate_->ForwardEvent(port->peer_node_name, + base::MakeUnique<ObserveProxyEvent>( + port->peer_port_name, name_, port_name, + port->peer_node_name, port->peer_port_name)); } void Node::MaybeRemoveProxy_Locked(const LockedPort& port, @@ -1227,9 +1184,9 @@ if (port->send_on_proxy_removal) { NodeName to_node = port->send_on_proxy_removal->first; - ScopedMessage& message = port->send_on_proxy_removal->second; + ScopedEvent& event = port->send_on_proxy_removal->second; - delegate_->ForwardMessage(to_node, std::move(message)); + delegate_->ForwardEvent(to_node, std::move(event)); port->send_on_proxy_removal.reset(); } } else { @@ -1241,7 +1198,7 @@ void Node::TryRemoveProxy(PortRef port_ref) { Port* port = port_ref.port(); bool should_erase = false; - ScopedMessage msg; + ScopedEvent event; NodeName to_node; { base::AutoLock lock(port->lock); @@ -1262,7 +1219,7 @@ if (port->send_on_proxy_removal) { to_node = port->send_on_proxy_removal->first; - msg = std::move(port->send_on_proxy_removal->second); + event = std::move(port->send_on_proxy_removal->second); port->send_on_proxy_removal.reset(); } } else { @@ -1274,8 +1231,8 @@ if (should_erase) ErasePort(port_ref.name()); - if (msg) - delegate_->ForwardMessage(to_node, std::move(msg)); + if (event) + delegate_->ForwardEvent(to_node, std::move(event)); } void Node::DestroyAllPortsWithPeer(const NodeName& node_name, @@ -1339,13 +1296,9 @@ for (const auto& proxy_name : dead_proxies_to_broadcast) { // Broadcast an event signifying that this proxy is no longer functioning. - ObserveProxyEventData event; - event.proxy_node_name = name_; - event.proxy_port_name = proxy_name; - event.proxy_to_node_name = kInvalidNodeName; - event.proxy_to_port_name = kInvalidPortName; - delegate_->BroadcastMessage(NewInternalMessage( - kInvalidPortName, EventType::kObserveProxy, event)); + delegate_->BroadcastEvent(base::MakeUnique<ObserveProxyEvent>( + kInvalidPortName, name_, proxy_name, kInvalidNodeName, + kInvalidPortName)); // Also process death locally since the port that points this closed one // could be on the current node. @@ -1362,24 +1315,6 @@ } } -ScopedMessage Node::NewInternalMessage_Helper(const PortName& port_name, - const EventType& type, - const void* data, - size_t num_data_bytes) { - ScopedMessage message; - delegate_->AllocMessage(sizeof(EventHeader) + num_data_bytes, &message); - - EventHeader* header = GetMutableEventHeader(message.get()); - header->port_name = port_name; - header->type = type; - header->padding = 0; - - if (num_data_bytes) - memcpy(header + 1, data, num_data_bytes); - - return message; -} - } // namespace ports } // namespace edk } // namespace mojo
diff --git a/mojo/edk/system/ports/node.h b/mojo/edk/system/ports/node.h index 55b8d27..7970279 100644 --- a/mojo/edk/system/ports/node.h +++ b/mojo/edk/system/ports/node.h
@@ -15,14 +15,11 @@ #include "base/memory/ref_counted.h" #include "base/synchronization/lock.h" #include "mojo/edk/system/ports/event.h" -#include "mojo/edk/system/ports/message.h" #include "mojo/edk/system/ports/name.h" #include "mojo/edk/system/ports/port.h" #include "mojo/edk/system/ports/port_ref.h" #include "mojo/edk/system/ports/user_data.h" -#undef SendMessage // Gah, windows - namespace mojo { namespace edk { namespace ports { @@ -114,16 +111,17 @@ // available. Ownership of |filter| is not taken, and it must outlive the // extent of this call. int GetMessage(const PortRef& port_ref, - ScopedMessage* message, + std::unique_ptr<UserMessageEvent>* message, MessageFilter* filter); // Sends a message from the specified port to its peer. Note that the message // notification may arrive synchronously (via PortStatusChanged() on the // delegate) if the peer is local to this Node. - int SendMessage(const PortRef& port_ref, ScopedMessage message); + int SendUserMessage(const PortRef& port_ref, + std::unique_ptr<UserMessageEvent> message); - // Corresponding to NodeDelegate::ForwardMessage. - int AcceptMessage(ScopedMessage message); + // Corresponding to NodeDelegate::ForwardEvent. + int AcceptEvent(ScopedEvent event); // Called to merge two ports with each other. If you have two independent // port pairs A <=> B and C <=> D, the net result of merging B and C is a @@ -155,13 +153,12 @@ // Note: Functions that end with _Locked require |ports_lock_| to be held // before calling. - int OnUserMessage(ScopedMessage message); - int OnPortAccepted(const PortName& port_name); - int OnObserveProxy(const PortName& port_name, - const ObserveProxyEventData& event); - int OnObserveProxyAck(const PortName& port_name, uint64_t last_sequence_num); - int OnObserveClosure(const PortName& port_name, uint64_t last_sequence_num); - int OnMergePort(const PortName& port_name, const MergePortEventData& event); + int OnUserMessage(std::unique_ptr<UserMessageEvent> message); + int OnPortAccepted(std::unique_ptr<PortAcceptedEvent> event); + int OnObserveProxy(std::unique_ptr<ObserveProxyEvent> event); + int OnObserveProxyAck(std::unique_ptr<ObserveProxyAckEvent> event); + int OnObserveClosure(std::unique_ptr<ObserveClosureEvent> event); + int OnMergePort(std::unique_ptr<MergePortEvent> event); int AddPortWithName(const PortName& port_name, scoped_refptr<Port> port); void ErasePort(const PortName& port_name); @@ -169,18 +166,19 @@ scoped_refptr<Port> GetPort(const PortName& port_name); scoped_refptr<Port> GetPort_Locked(const PortName& port_name); - int SendMessageInternal(const PortRef& port_ref, ScopedMessage* message); + int SendUserMessageInternal(const PortRef& port_ref, + std::unique_ptr<UserMessageEvent>* message); int MergePorts_Locked(const PortRef& port0_ref, const PortRef& port1_ref); void WillSendPort(const LockedPort& port, const NodeName& to_node_name, PortName* port_name, - PortDescriptor* port_descriptor); + Event::PortDescriptor* port_descriptor); int AcceptPort(const PortName& port_name, - const PortDescriptor& port_descriptor); + const Event::PortDescriptor& port_descriptor); - int WillSendMessage_Locked(const LockedPort& port, - const PortName& port_name, - Message* message); + int WillForwardUserMessage_Locked(const LockedPort& port, + const PortName& port_name, + UserMessageEvent* message); int BeginProxying_Locked(const LockedPort& port, const PortName& port_name); int BeginProxying(PortRef port_ref); int ForwardMessages_Locked(const LockedPort& port, const PortName& port_name); @@ -191,30 +189,13 @@ void DestroyAllPortsWithPeer(const NodeName& node_name, const PortName& port_name); - ScopedMessage NewInternalMessage_Helper(const PortName& port_name, - const EventType& type, - const void* data, - size_t num_data_bytes); - - ScopedMessage NewInternalMessage(const PortName& port_name, - const EventType& type) { - return NewInternalMessage_Helper(port_name, type, nullptr, 0); - } - - template <typename EventData> - ScopedMessage NewInternalMessage(const PortName& port_name, - const EventType& type, - const EventData& data) { - return NewInternalMessage_Helper(port_name, type, &data, sizeof(data)); - } - const NodeName name_; NodeDelegate* const delegate_; // Guards |ports_| as well as any operation which needs to hold multiple port // locks simultaneously. Usage of this is subtle: it must NEVER be acquired // after a Port lock is acquired, and it must ALWAYS be acquired before - // calling WillSendMessage_Locked or ForwardMessages_Locked. + // calling WillForwardUserMessage_Locked or ForwardMessages_Locked. base::Lock ports_lock_; std::unordered_map<PortName, scoped_refptr<Port>> ports_;
diff --git a/mojo/edk/system/ports/node_delegate.h b/mojo/edk/system/ports/node_delegate.h index 8547302a..13f264f 100644 --- a/mojo/edk/system/ports/node_delegate.h +++ b/mojo/edk/system/ports/node_delegate.h
@@ -7,7 +7,7 @@ #include <stddef.h> -#include "mojo/edk/system/ports/message.h" +#include "mojo/edk/system/ports/event.h" #include "mojo/edk/system/ports/name.h" #include "mojo/edk/system/ports/port_ref.h" @@ -22,18 +22,12 @@ // Port names should be difficult to guess. virtual void GenerateRandomPortName(PortName* port_name) = 0; - // Allocate a message, including a header that can be used by the Node - // implementation. |num_header_bytes| will be aligned. The newly allocated - // memory need not be zero-filled. - virtual void AllocMessage(size_t num_header_bytes, - ScopedMessage* message) = 0; + // Forward an event asynchronously to the specified node. This method MUST NOT + // synchronously call any methods on Node. + virtual void ForwardEvent(const NodeName& node, ScopedEvent event) = 0; - // Forward a message asynchronously to the specified node. This method MUST - // NOT synchronously call any methods on Node. - virtual void ForwardMessage(const NodeName& node, ScopedMessage message) = 0; - - // Broadcast a message to all nodes. - virtual void BroadcastMessage(ScopedMessage message) = 0; + // Broadcast an event to all nodes. + virtual void BroadcastEvent(ScopedEvent event) = 0; // Indicates that the port's status has changed recently. Use Node::GetStatus // to query the latest status of the port. Note, this event could be spurious
diff --git a/mojo/edk/system/ports/port.h b/mojo/edk/system/ports/port.h index ea53d43..aa16d3b1 100644 --- a/mojo/edk/system/ports/port.h +++ b/mojo/edk/system/ports/port.h
@@ -13,6 +13,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/synchronization/lock.h" +#include "mojo/edk/system/ports/event.h" #include "mojo/edk/system/ports/message_queue.h" #include "mojo/edk/system/ports/user_data.h" @@ -37,7 +38,7 @@ uint64_t next_sequence_num_to_send; uint64_t last_sequence_num_to_receive; MessageQueue message_queue; - std::unique_ptr<std::pair<NodeName, ScopedMessage>> send_on_proxy_removal; + std::unique_ptr<std::pair<NodeName, ScopedEvent>> send_on_proxy_removal; scoped_refptr<UserData> user_data; bool remove_proxy_on_last_message; bool peer_closed;
diff --git a/mojo/edk/system/ports/ports_unittest.cc b/mojo/edk/system/ports/ports_unittest.cc index 4b384b4..e20fda38 100644 --- a/mojo/edk/system/ports/ports_unittest.cc +++ b/mojo/edk/system/ports/ports_unittest.cc
@@ -26,6 +26,7 @@ #include "mojo/edk/system/ports/event.h" #include "mojo/edk/system/ports/node.h" #include "mojo/edk/system/ports/node_delegate.h" +#include "mojo/edk/system/ports/user_message.h" #include "testing/gtest/include/gtest/gtest.h" namespace mojo { @@ -35,36 +36,35 @@ namespace { -bool MessageEquals(const ScopedMessage& message, const base::StringPiece& s) { - return !strcmp(static_cast<const char*>(message->payload_bytes()), s.data()); +// TODO(rockot): Remove this unnecessary alias. +using ScopedMessage = std::unique_ptr<UserMessageEvent>; + +class TestMessage : public UserMessage { + public: + static const TypeInfo kUserMessageTypeInfo; + + TestMessage(const base::StringPiece& payload) + : UserMessage(&kUserMessageTypeInfo), payload_(payload) {} + ~TestMessage() override {} + + const std::string& payload() const { return payload_; } + + private: + std::string payload_; +}; + +const UserMessage::TypeInfo TestMessage::kUserMessageTypeInfo = {}; + +ScopedMessage NewUserMessageEvent(const base::StringPiece& payload, + size_t num_ports) { + auto event = base::MakeUnique<UserMessageEvent>(num_ports); + event->AttachMessage(base::MakeUnique<TestMessage>(payload)); + return event; } -class TestMessage : public Message { - public: - static ScopedMessage NewUserMessage(size_t num_payload_bytes, - size_t num_ports) { - return ScopedMessage(new TestMessage(num_payload_bytes, num_ports)); - } - - TestMessage(size_t num_payload_bytes, size_t num_ports) - : Message(num_payload_bytes, num_ports) { - start_ = new char[num_header_bytes_ + num_ports_bytes_ + num_payload_bytes]; - InitializeUserMessageHeader(start_); - } - - TestMessage(size_t num_header_bytes, - size_t num_payload_bytes, - size_t num_ports_bytes) - : Message(num_header_bytes, - num_payload_bytes, - num_ports_bytes) { - start_ = new char[num_header_bytes + num_payload_bytes + num_ports_bytes]; - } - - ~TestMessage() override { - delete[] start_; - } -}; +bool MessageEquals(const ScopedMessage& message, const base::StringPiece& s) { + return message->GetMessage<TestMessage>()->payload() == s; +} class TestNode; @@ -73,10 +73,10 @@ virtual ~MessageRouter() {} virtual void GeneratePortName(PortName* name) = 0; - virtual void ForwardMessage(TestNode* from_node, - const NodeName& node_name, - ScopedMessage message) = 0; - virtual void BroadcastMessage(TestNode* from_node, ScopedMessage message) = 0; + virtual void ForwardEvent(TestNode* from_node, + const NodeName& node_name, + ScopedEvent event) = 0; + virtual void BroadcastEvent(TestNode* from_node, ScopedEvent event) = 0; }; class TestNode : public NodeDelegate { @@ -85,13 +85,11 @@ : node_name_(id, 1), node_(node_name_, this), node_thread_(base::StringPrintf("Node %" PRIu64 " thread", id)), - messages_available_event_( + events_available_event_( base::WaitableEvent::ResetPolicy::AUTOMATIC, base::WaitableEvent::InitialState::NOT_SIGNALED), - idle_event_( - base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::SIGNALED) { - } + idle_event_(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::SIGNALED) {} ~TestNode() override { StopWhenIdle(); @@ -108,10 +106,10 @@ bool IsIdle() { base::AutoLock lock(lock_); return started_ && !dispatching_ && - (incoming_messages_.empty() || (block_on_event_ && blocked_)); + (incoming_events_.empty() || (block_on_event_ && blocked_)); } - void BlockOnEvent(EventType type) { + void BlockOnEvent(Event::Type type) { base::AutoLock lock(lock_); blocked_event_type_ = type; block_on_event_ = true; @@ -120,7 +118,7 @@ void Unblock() { base::AutoLock lock(lock_); block_on_event_ = false; - messages_available_event_.Signal(); + events_available_event_.Signal(); } void Start(MessageRouter* router) { @@ -128,32 +126,27 @@ node_thread_.Start(); node_thread_.task_runner()->PostTask( FROM_HERE, - base::Bind(&TestNode::ProcessMessages, base::Unretained(this))); + base::Bind(&TestNode::ProcessEvents, base::Unretained(this))); } void StopWhenIdle() { base::AutoLock lock(lock_); should_quit_ = true; - messages_available_event_.Signal(); + events_available_event_.Signal(); } - void WakeUp() { messages_available_event_.Signal(); } + void WakeUp() { events_available_event_.Signal(); } int SendStringMessage(const PortRef& port, const std::string& s) { - size_t size = s.size() + 1; - ScopedMessage message = TestMessage::NewUserMessage(size, 0); - memcpy(message->mutable_payload_bytes(), s.data(), size); - return node_.SendMessage(port, std::move(message)); + return node_.SendUserMessage(port, NewUserMessageEvent(s, 0)); } int SendStringMessageWithPort(const PortRef& port, const std::string& s, const PortName& sent_port_name) { - size_t size = s.size() + 1; - ScopedMessage message = TestMessage::NewUserMessage(size, 1); - memcpy(message->mutable_payload_bytes(), s.data(), size); - message->mutable_ports()[0] = sent_port_name; - return node_.SendMessage(port, std::move(message)); + auto event = NewUserMessageEvent(s, 1); + event->ports()[0] = sent_port_name; + return node_.SendUserMessage(port, std::move(event)); } int SendStringMessageWithPort(const PortRef& port, @@ -187,14 +180,14 @@ return true; } - void EnqueueMessage(ScopedMessage message) { + void EnqueueEvent(ScopedEvent event) { idle_event_.Reset(); // NOTE: This may be called from ForwardMessage and thus must not reenter // |node_|. base::AutoLock lock(lock_); - incoming_messages_.emplace(std::move(message)); - messages_available_event_.Signal(); + incoming_events_.emplace(std::move(event)); + events_available_event_.Signal(); } void GenerateRandomPortName(PortName* port_name) override { @@ -202,12 +195,7 @@ router_->GeneratePortName(port_name); } - void AllocMessage(size_t num_header_bytes, ScopedMessage* message) override { - message->reset(new TestMessage(num_header_bytes, 0, 0)); - } - - void ForwardMessage(const NodeName& node_name, - ScopedMessage message) override { + void ForwardEvent(const NodeName& node_name, ScopedEvent event) override { { base::AutoLock lock(lock_); if (drop_messages_) { @@ -215,19 +203,18 @@ << node_name_ << " to " << node_name; base::AutoUnlock unlock(lock_); - ClosePortsInMessage(message.get()); + ClosePortsInEvent(event.get()); return; } } DCHECK(router_); - DVLOG(1) << "ForwardMessage from node " - << node_name_ << " to " << node_name; - router_->ForwardMessage(this, node_name, std::move(message)); + DVLOG(1) << "ForwardEvent from node " << node_name_ << " to " << node_name; + router_->ForwardEvent(this, node_name, std::move(event)); } - void BroadcastMessage(ScopedMessage message) override { - router_->BroadcastMessage(this, std::move(message)); + void BroadcastEvent(ScopedEvent event) override { + router_->BroadcastEvent(this, std::move(event)); } void PortStatusChanged(const PortRef& port) override { @@ -248,42 +235,44 @@ } } - void ClosePortsInMessage(Message* message) { - for (size_t i = 0; i < message->num_ports(); ++i) { + void ClosePortsInEvent(Event* event) { + if (event->type() != Event::Type::kUserMessage) + return; + + UserMessageEvent* message_event = static_cast<UserMessageEvent*>(event); + for (size_t i = 0; i < message_event->num_ports(); ++i) { PortRef port; - ASSERT_EQ(OK, node_.GetPort(message->ports()[i], &port)); + ASSERT_EQ(OK, node_.GetPort(message_event->ports()[i], &port)); EXPECT_EQ(OK, node_.ClosePort(port)); } } private: - void ProcessMessages() { + void ProcessEvents() { for (;;) { - messages_available_event_.Wait(); - + events_available_event_.Wait(); base::AutoLock lock(lock_); if (should_quit_) return; dispatching_ = true; - while (!incoming_messages_.empty()) { + while (!incoming_events_.empty()) { if (block_on_event_ && - GetEventHeader(*incoming_messages_.front())->type == - blocked_event_type_) { + incoming_events_.front()->type() == blocked_event_type_) { blocked_ = true; // Go idle if we hit a blocked event type. break; } else { blocked_ = false; } - ScopedMessage message = std::move(incoming_messages_.front()); - incoming_messages_.pop(); + ScopedEvent event = std::move(incoming_events_.front()); + incoming_events_.pop(); // NOTE: AcceptMessage() can re-enter this object to call any of the // NodeDelegate interface methods. base::AutoUnlock unlock(lock_); - node_.AcceptMessage(std::move(message)); + node_.AcceptEvent(std::move(event)); } dispatching_ = false; @@ -297,7 +286,7 @@ MessageRouter* router_ = nullptr; base::Thread node_thread_; - base::WaitableEvent messages_available_event_; + base::WaitableEvent events_available_event_; base::WaitableEvent idle_event_; // Guards fields below. @@ -309,8 +298,8 @@ bool save_messages_ = false; bool blocked_ = false; bool block_on_event_ = false; - EventType blocked_event_type_; - std::queue<ScopedMessage> incoming_messages_; + Event::Type blocked_event_type_; + std::queue<ScopedEvent> incoming_events_; std::queue<ScopedMessage> saved_messages_; }; @@ -384,14 +373,14 @@ name->v2 = 0; } - void ForwardMessage(TestNode* from_node, - const NodeName& node_name, - ScopedMessage message) override { + void ForwardEvent(TestNode* from_node, + const NodeName& node_name, + ScopedEvent event) override { base::AutoLock global_lock(global_lock_); base::AutoLock lock(lock_); // Drop messages from nodes that have been removed. if (nodes_.find(from_node->name()) == nodes_.end()) { - from_node->ClosePortsInMessage(message.get()); + from_node->ClosePortsInEvent(event.get()); return; } @@ -401,10 +390,10 @@ return; } - it->second->EnqueueMessage(std::move(message)); + it->second->EnqueueEvent(std::move(event)); } - void BroadcastMessage(TestNode* from_node, ScopedMessage message) override { + void BroadcastEvent(TestNode* from_node, ScopedEvent event) override { base::AutoLock global_lock(global_lock_); base::AutoLock lock(lock_); @@ -417,14 +406,7 @@ // Broadcast doesn't deliver to the local node. if (node == from_node) continue; - - // NOTE: We only need to support broadcast of events. Events have no - // payload or ports bytes. - ScopedMessage new_message( - new TestMessage(message->num_header_bytes(), 0, 0)); - memcpy(new_message->mutable_header_bytes(), message->header_bytes(), - message->num_header_bytes()); - node->EnqueueMessage(std::move(new_message)); + node->EnqueueEvent(event->Clone()); } } @@ -592,7 +574,7 @@ EXPECT_EQ(OK, node1.node().GetMessage(x1, &message, nullptr)); EXPECT_TRUE(message); - node1.ClosePortsInMessage(message.get()); + node1.ClosePortsInEvent(message.get()); EXPECT_EQ(OK, node1.node().ClosePort(x1)); @@ -638,7 +620,7 @@ // port A on node 0 will eventually also become aware of it. // Make sure node2 stops processing events when it encounters an ObserveProxy. - node2.BlockOnEvent(EventType::kObserveProxy); + node2.BlockOnEvent(Event::Type::kObserveProxy); EXPECT_EQ(OK, node1.SendStringMessageWithPort(C, ".", F)); WaitForIdle(); @@ -687,7 +669,7 @@ EXPECT_EQ(OK, node0.node().CreatePortPair(&C, &D)); // Send D but block node0 on an ObserveProxy event. - node0.BlockOnEvent(EventType::kObserveProxy); + node0.BlockOnEvent(Event::Type::kObserveProxy); EXPECT_EQ(OK, node0.SendStringMessageWithPort(A, ".", D)); // node0 won't collapse the proxy but node1 will receive the message before @@ -888,7 +870,7 @@ bool got_hello = false; ScopedMessage message; while (node1.GetSavedMessage(&message)) { - node1.ClosePortsInMessage(message.get()); + node1.ClosePortsInEvent(message.get()); if (MessageEquals(message, "hello")) { got_hello = true; break; @@ -1433,7 +1415,7 @@ // Block the merge from proceeding until we can do something stupid with port // C. This avoids the test logic racing with async merge logic. - node1.BlockOnEvent(EventType::kMergePort); + node1.BlockOnEvent(Event::Type::kMergePort); // Initiate the merge between B and C. EXPECT_EQ(OK, node0.node().MergePorts(B, node1.name(), C.name()));
diff --git a/mojo/edk/system/ports/user_message.h b/mojo/edk/system/ports/user_message.h new file mode 100644 index 0000000..1401e59 --- /dev/null +++ b/mojo/edk/system/ports/user_message.h
@@ -0,0 +1,44 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_EDK_SYSTEM_PORTS_USER_MESSAGE_H_ +#define MOJO_EDK_SYSTEM_PORTS_USER_MESSAGE_H_ + +#include "base/macros.h" + +namespace mojo { +namespace edk { +namespace ports { + +// Base type to use for any embedder-defined user message implementation. This +// class is intentionally empty. +// +// Provides a bit of type-safety help to subclasses since by design downcasting +// from this type is a common operation in embedders. +// +// Each subclass should define a static const instance of TypeInfo named +// |kUserMessageTypeInfo| and pass its address down to the UserMessage +// constructor. The type of a UserMessage can then be dynamically inspected by +// comparing |type_info()| to any subclass's |&kUserMessageTypeInfo|. +class UserMessage { + public: + struct TypeInfo {}; + + virtual ~UserMessage() {} + + explicit UserMessage(const TypeInfo* type_info) : type_info_(type_info) {} + + const TypeInfo* type_info() const { return type_info_; } + + private: + const TypeInfo* const type_info_; + + DISALLOW_COPY_AND_ASSIGN(UserMessage); +}; + +} // namespace ports +} // namespace edk +} // namespace mojo + +#endif // MOJO_EDK_SYSTEM_PORTS_USER_MESSAGE_H_
diff --git a/mojo/edk/system/ports_message.cc b/mojo/edk/system/ports_message.cc deleted file mode 100644 index 5f3e8c01..0000000 --- a/mojo/edk/system/ports_message.cc +++ /dev/null
@@ -1,62 +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 "mojo/edk/system/ports_message.h" - -#include "base/memory/ptr_util.h" -#include "mojo/edk/system/node_channel.h" - -namespace mojo { -namespace edk { - -// static -std::unique_ptr<PortsMessage> PortsMessage::NewUserMessage( - size_t num_payload_bytes, - size_t num_ports, - size_t num_handles) { - return base::WrapUnique( - new PortsMessage(num_payload_bytes, num_ports, num_handles)); -} - -PortsMessage::~PortsMessage() {} - -PortsMessage::PortsMessage(size_t num_payload_bytes, - size_t num_ports, - size_t num_handles) - : ports::Message(num_payload_bytes, num_ports) { - size_t size = num_header_bytes_ + num_ports_bytes_ + num_payload_bytes; - void* ptr; - channel_message_ = NodeChannel::CreatePortsMessage(size, &ptr, num_handles); - InitializeUserMessageHeader(ptr); -} - -PortsMessage::PortsMessage(size_t num_header_bytes, - size_t num_payload_bytes, - size_t num_ports_bytes, - Channel::MessagePtr channel_message) - : ports::Message(num_header_bytes, - num_payload_bytes, - num_ports_bytes) { - if (channel_message) { - channel_message_ = std::move(channel_message); - void* data; - size_t num_data_bytes; - NodeChannel::GetPortsMessageData(channel_message_.get(), &data, - &num_data_bytes); - start_ = static_cast<char*>(data); - } else { - // TODO: Clean this up. In practice this branch of the constructor should - // only be reached from Node-internal calls to AllocMessage, which never - // carry ports or non-header bytes. - CHECK_EQ(num_payload_bytes, 0u); - CHECK_EQ(num_ports_bytes, 0u); - void* ptr; - channel_message_ = - NodeChannel::CreatePortsMessage(num_header_bytes, &ptr, 0); - start_ = static_cast<char*>(ptr); - } -} - -} // namespace edk -} // namespace mojo
diff --git a/mojo/edk/system/ports_message.h b/mojo/edk/system/ports_message.h deleted file mode 100644 index 542b981..0000000 --- a/mojo/edk/system/ports_message.h +++ /dev/null
@@ -1,69 +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 MOJO_EDK_SYSTEM_PORTS_MESSAGE_H__ -#define MOJO_EDK_SYSTEM_PORTS_MESSAGE_H__ - -#include <memory> -#include <utility> - -#include "mojo/edk/embedder/platform_handle_vector.h" -#include "mojo/edk/system/channel.h" -#include "mojo/edk/system/ports/message.h" -#include "mojo/edk/system/ports/name.h" - -namespace mojo { -namespace edk { - -class NodeController; - -class PortsMessage : public ports::Message { - public: - static std::unique_ptr<PortsMessage> NewUserMessage(size_t num_payload_bytes, - size_t num_ports, - size_t num_handles); - - ~PortsMessage() override; - - size_t num_handles() const { return channel_message_->num_handles(); } - bool has_handles() const { return channel_message_->has_handles(); } - - void SetHandles(ScopedPlatformHandleVectorPtr handles) { - channel_message_->SetHandles(std::move(handles)); - } - - ScopedPlatformHandleVectorPtr TakeHandles() { - return channel_message_->TakeHandles(); - } - - Channel::MessagePtr TakeChannelMessage() { - return std::move(channel_message_); - } - - void set_source_node(const ports::NodeName& name) { source_node_ = name; } - const ports::NodeName& source_node() const { return source_node_; } - - private: - friend class NodeController; - - // Construct a new user PortsMessage backed by a new Channel::Message. - PortsMessage(size_t num_payload_bytes, size_t num_ports, size_t num_handles); - - // Construct a new PortsMessage backed by a Channel::Message. If - // |channel_message| is null, a new one is allocated internally. - PortsMessage(size_t num_header_bytes, - size_t num_payload_bytes, - size_t num_ports_bytes, - Channel::MessagePtr channel_message); - - Channel::MessagePtr channel_message_; - - // The node name from which this message was received, if known. - ports::NodeName source_node_ = ports::kInvalidNodeName; -}; - -} // namespace edk -} // namespace mojo - -#endif // MOJO_EDK_SYSTEM_PORTS_MESSAGE_H__
diff --git a/mojo/edk/system/user_message_impl.cc b/mojo/edk/system/user_message_impl.cc new file mode 100644 index 0000000..44d9bb8 --- /dev/null +++ b/mojo/edk/system/user_message_impl.cc
@@ -0,0 +1,457 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/edk/system/user_message_impl.h" + +#include "base/memory/ptr_util.h" +#include "base/numerics/safe_conversions.h" +#include "base/numerics/safe_math.h" +#include "mojo/edk/system/core.h" +#include "mojo/edk/system/node_channel.h" +#include "mojo/edk/system/node_controller.h" +#include "mojo/edk/system/ports/event.h" +#include "mojo/edk/system/ports/message_filter.h" +#include "mojo/edk/system/ports/node.h" + +namespace mojo { +namespace edk { + +namespace { + +#pragma pack(push, 1) +// Header attached to every message. +struct MessageHeader { + // The number of serialized dispatchers included in this header. + uint32_t num_dispatchers; + + // Total size of the header, including serialized dispatcher data. + uint32_t header_size; +}; + +// Header for each dispatcher in a message, immediately following the message +// header. +struct DispatcherHeader { + // The type of the dispatcher, correpsonding to the Dispatcher::Type enum. + int32_t type; + + // The size of the serialized dispatcher, not including this header. + uint32_t num_bytes; + + // The number of ports needed to deserialize this dispatcher. + uint32_t num_ports; + + // The number of platform handles needed to deserialize this dispatcher. + uint32_t num_platform_handles; +}; +#pragma pack(pop) + +static_assert(sizeof(MessageHeader) % 8 == 0, "Invalid MessageHeader size."); +static_assert(sizeof(DispatcherHeader) % 8 == 0, + "Invalid DispatcherHeader size."); + +} // namespace + +// A MessageFilter used by UserMessageImpl::ReadMessageEventFromPort to +// determine whether a message should actually be consumed yet. +class UserMessageImpl::ReadMessageFilter : public ports::MessageFilter { + public: + // Creates a new ReadMessageFilter which captures and potentially modifies + // various (unowned) local state within + // UserMessageImpl::ReadMessageEventFromPort. + ReadMessageFilter(bool read_any_size, + bool may_discard, + uint32_t* num_bytes, + uint32_t* num_handles, + bool* no_space, + bool* invalid_message) + : read_any_size_(read_any_size), + may_discard_(may_discard), + num_bytes_(num_bytes), + num_handles_(num_handles), + no_space_(no_space), + invalid_message_(invalid_message) {} + + ~ReadMessageFilter() override {} + + // ports::MessageFilter: + bool Match(const ports::UserMessageEvent& event) override { + const auto* message = event.GetMessage<UserMessageImpl>(); + if (!message->IsSerialized()) { + // Not a serialized message, so there's nothing to validate or filter + // against. We only ensure that the caller expected a message object and + // not a specific serialized buffer size. + if (!read_any_size_) + *invalid_message_ = true; + return true; + } + + // All messages which reach this filter have already had a basic level of + // validation applied by UserMessageImpl::CreateFromChannelMessage() + // so we know there is at least well-formed header. + DCHECK(message->header_); + auto* header = static_cast<MessageHeader*>(message->header_); + + uint32_t bytes_to_read = 0; + base::CheckedNumeric<uint32_t> checked_bytes_available = + message->user_payload_size(); + if (!checked_bytes_available.IsValid()) { + *invalid_message_ = true; + return true; + } + const uint32_t bytes_available = checked_bytes_available.ValueOrDie(); + if (num_bytes_) { + bytes_to_read = std::min(*num_bytes_, bytes_available); + *num_bytes_ = bytes_available; + } + + uint32_t handles_to_read = 0; + uint32_t handles_available = header->num_dispatchers; + if (num_handles_) { + handles_to_read = std::min(*num_handles_, handles_available); + *num_handles_ = handles_available; + } + + if (handles_to_read < handles_available || + (!read_any_size_ && bytes_to_read < bytes_available)) { + *no_space_ = true; + return may_discard_; + } + + return true; + } + + private: + const bool read_any_size_; + const bool may_discard_; + uint32_t* const num_bytes_; + uint32_t* const num_handles_; + bool* const no_space_; + bool* const invalid_message_; + + DISALLOW_COPY_AND_ASSIGN(ReadMessageFilter); +}; + +// static +const ports::UserMessage::TypeInfo UserMessageImpl::kUserMessageTypeInfo = {}; + +UserMessageImpl::~UserMessageImpl() {} + +// static +MojoResult UserMessageImpl::CreateEventForNewSerializedMessage( + uint32_t num_bytes, + const Dispatcher::DispatcherInTransit* dispatchers, + uint32_t num_dispatchers, + std::unique_ptr<ports::UserMessageEvent>* out_event) { + // A structure for retaining information about every Dispatcher that will be + // serialized into this message. + struct DispatcherInfo { + uint32_t num_bytes; + uint32_t num_ports; + uint32_t num_handles; + }; + + // This is only the base header size. It will grow as we accumulate the + // size of serialized state for each dispatcher. + size_t header_size = + sizeof(MessageHeader) + num_dispatchers * sizeof(DispatcherHeader); + size_t num_ports = 0; + size_t num_handles = 0; + + std::vector<DispatcherInfo> dispatcher_info(num_dispatchers); + for (size_t i = 0; i < num_dispatchers; ++i) { + Dispatcher* d = dispatchers[i].dispatcher.get(); + d->StartSerialize(&dispatcher_info[i].num_bytes, + &dispatcher_info[i].num_ports, + &dispatcher_info[i].num_handles); + header_size += dispatcher_info[i].num_bytes; + num_ports += dispatcher_info[i].num_ports; + num_handles += dispatcher_info[i].num_handles; + } + + // We now have enough information to fully allocate the message storage. + auto message_event = base::MakeUnique<ports::UserMessageEvent>(num_ports); + auto message = base::WrapUnique( + new UserMessageImpl(message_event->GetSerializedSize(), header_size, + num_bytes, num_ports, num_handles)); + + // Populate the message header with information about serialized dispatchers. + // The front of the message is always a MessageHeader followed by a + // DispatcherHeader for each dispatcher to be sent. + MessageHeader* header = static_cast<MessageHeader*>(message->header_); + DispatcherHeader* dispatcher_headers = + reinterpret_cast<DispatcherHeader*>(header + 1); + + // Serialized dispatcher state immediately follows the series of + // DispatcherHeaders. + char* dispatcher_data = + reinterpret_cast<char*>(dispatcher_headers + num_dispatchers); + + header->num_dispatchers = num_dispatchers; + + // |header_size| is the total number of bytes preceding the message payload, + // including all dispatcher headers and serialized dispatcher state. + if (!base::IsValueInRangeForNumericType<uint32_t>(header_size)) + return MOJO_RESULT_OUT_OF_RANGE; + + header->header_size = static_cast<uint32_t>(header_size); + + if (num_dispatchers > 0) { + ScopedPlatformHandleVectorPtr handles( + new PlatformHandleVector(num_handles)); + size_t port_index = 0; + size_t handle_index = 0; + bool fail = false; + for (size_t i = 0; i < num_dispatchers; ++i) { + Dispatcher* d = dispatchers[i].dispatcher.get(); + DispatcherHeader* dh = &dispatcher_headers[i]; + const DispatcherInfo& info = dispatcher_info[i]; + + // Fill in the header for this dispatcher. + dh->type = static_cast<int32_t>(d->GetType()); + dh->num_bytes = info.num_bytes; + dh->num_ports = info.num_ports; + dh->num_platform_handles = info.num_handles; + + // Fill in serialized state, ports, and platform handles. We'll cancel + // the send if the dispatcher implementation rejects for some reason. + if (!d->EndSerialize(static_cast<void*>(dispatcher_data), + message_event->ports() + port_index, + handles->data() + handle_index)) { + fail = true; + break; + } + + dispatcher_data += info.num_bytes; + port_index += info.num_ports; + handle_index += info.num_handles; + } + + if (fail) { + // Release any platform handles we've accumulated. Their dispatchers + // retain ownership when message creation fails, so these are not actually + // leaking. + handles->clear(); + return MOJO_RESULT_INVALID_ARGUMENT; + } + + // Take ownership of all the handles and move them into message storage. + message->channel_message_->SetHandles(std::move(handles)); + } + + message_event->AttachMessage(std::move(message)); + *out_event = std::move(message_event); + return MOJO_RESULT_OK; +} + +// static +std::unique_ptr<UserMessageImpl> UserMessageImpl::CreateFromChannelMessage( + Channel::MessagePtr channel_message, + void* payload, + size_t payload_size) { + DCHECK(channel_message); + if (payload_size < sizeof(MessageHeader)) + return nullptr; + + auto* header = static_cast<MessageHeader*>(payload); + const size_t header_size = header->header_size; + if (header_size > payload_size) + return nullptr; + + void* user_payload = static_cast<uint8_t*>(payload) + header_size; + const size_t user_payload_size = payload_size - header_size; + return base::WrapUnique(new UserMessageImpl( + std::move(channel_message), header, user_payload, user_payload_size)); +} + +// static +MojoResult UserMessageImpl::ReadMessageEventFromPort( + NodeController* node_controller, + const ports::PortRef& port, + bool read_any_size, + bool may_discard, + uint32_t* num_bytes, + MojoHandle* handles, + uint32_t* num_handles, + std::unique_ptr<ports::UserMessageEvent>* out_event) { + bool no_space = false; + bool invalid_message = false; + ReadMessageFilter filter(read_any_size, may_discard, num_bytes, num_handles, + &no_space, &invalid_message); + std::unique_ptr<ports::UserMessageEvent> message_event; + int rv = node_controller->node()->GetMessage(port, &message_event, &filter); + if (invalid_message) + return MOJO_RESULT_UNKNOWN; + + if (rv != ports::OK && rv != ports::ERROR_PORT_PEER_CLOSED) { + if (rv == ports::ERROR_PORT_UNKNOWN || + rv == ports::ERROR_PORT_STATE_UNEXPECTED) + return MOJO_RESULT_INVALID_ARGUMENT; + + NOTREACHED(); + return MOJO_RESULT_UNKNOWN; // TODO: Add a better error code here? + } + + if (no_space) { + // |*num_handles| (and/or |*num_bytes| if |read_any_size| is false) wasn't + // sufficient to hold this message's data. The message will still be in + // queue unless MOJO_READ_MESSAGE_FLAG_MAY_DISCARD was set. + return MOJO_RESULT_RESOURCE_EXHAUSTED; + } + + if (!message_event) { + // No message was available in queue. + if (rv == ports::OK) + return MOJO_RESULT_SHOULD_WAIT; + // Peer is closed and there are no more messages to read. + DCHECK_EQ(rv, ports::ERROR_PORT_PEER_CLOSED); + return MOJO_RESULT_FAILED_PRECONDITION; + } + + // Alright! We have a message and the caller has provided sufficient storage + // in which to receive it, if applicable. + + auto* message = message_event->GetMessage<UserMessageImpl>(); + if (message->HasContext()) { + // Not a serialized message, so there's no more work to do. + *out_event = std::move(message_event); + return MOJO_RESULT_OK; + } + + DCHECK(message->IsSerialized()); + + const MessageHeader* header = + static_cast<const MessageHeader*>(message->header_); + const DispatcherHeader* dispatcher_headers = + reinterpret_cast<const DispatcherHeader*>(header + 1); + + if (header->num_dispatchers > std::numeric_limits<uint16_t>::max()) + return MOJO_RESULT_UNKNOWN; + + // Deserialize dispatchers. + if (header->num_dispatchers > 0) { + DCHECK(handles); + std::vector<Dispatcher::DispatcherInTransit> dispatchers( + header->num_dispatchers); + + size_t data_payload_index = + sizeof(MessageHeader) + + header->num_dispatchers * sizeof(DispatcherHeader); + if (data_payload_index > header->header_size) + return MOJO_RESULT_UNKNOWN; + const char* dispatcher_data = reinterpret_cast<const char*>( + dispatcher_headers + header->num_dispatchers); + size_t port_index = 0; + size_t platform_handle_index = 0; + ScopedPlatformHandleVectorPtr msg_handles = + message->channel_message_->TakeHandles(); + const size_t num_msg_handles = msg_handles ? msg_handles->size() : 0; + for (size_t i = 0; i < header->num_dispatchers; ++i) { + const DispatcherHeader& dh = dispatcher_headers[i]; + auto type = static_cast<Dispatcher::Type>(dh.type); + + base::CheckedNumeric<size_t> next_payload_index = data_payload_index; + next_payload_index += dh.num_bytes; + if (!next_payload_index.IsValid() || + header->header_size < next_payload_index.ValueOrDie()) { + return MOJO_RESULT_UNKNOWN; + } + + base::CheckedNumeric<size_t> next_port_index = port_index; + next_port_index += dh.num_ports; + if (!next_port_index.IsValid() || + message_event->num_ports() < next_port_index.ValueOrDie()) { + return MOJO_RESULT_UNKNOWN; + } + + base::CheckedNumeric<size_t> next_platform_handle_index = + platform_handle_index; + next_platform_handle_index += dh.num_platform_handles; + if (!next_platform_handle_index.IsValid() || + num_msg_handles < next_platform_handle_index.ValueOrDie()) { + return MOJO_RESULT_UNKNOWN; + } + + PlatformHandle* out_handles = + num_msg_handles ? msg_handles->data() + platform_handle_index + : nullptr; + dispatchers[i].dispatcher = Dispatcher::Deserialize( + type, dispatcher_data, dh.num_bytes, + message_event->ports() + port_index, dh.num_ports, out_handles, + dh.num_platform_handles); + if (!dispatchers[i].dispatcher) + return MOJO_RESULT_UNKNOWN; + + dispatcher_data += dh.num_bytes; + data_payload_index = next_payload_index.ValueOrDie(); + port_index = next_port_index.ValueOrDie(); + platform_handle_index = next_platform_handle_index.ValueOrDie(); + } + + if (!node_controller->core()->AddDispatchersFromTransit(dispatchers, + handles)) { + return MOJO_RESULT_UNKNOWN; + } + } + + *out_event = std::move(message_event); + return MOJO_RESULT_OK; +} + +// static +Channel::MessagePtr UserMessageImpl::SerializeEventMessage( + std::unique_ptr<ports::UserMessageEvent> message_event) { + auto* message = message_event->GetMessage<UserMessageImpl>(); + Channel::MessagePtr channel_message; + if (message->IsSerialized()) { + DCHECK(message->channel_message_); + message->user_payload_ = nullptr; + message->user_payload_size_ = 0; + channel_message = std::move(message->channel_message_); + } else { + // TODO(crbug.com/725321): Implement lazy serialization. + NOTREACHED(); + return nullptr; + } + + // Serialize the UserMessageEvent into the front of the message payload where + // there is already space reserved for it. + void* data; + size_t size; + NodeChannel::GetEventMessageData(channel_message.get(), &data, &size); + message_event->Serialize(data); + return channel_message; +} + +size_t UserMessageImpl::num_handles() const { + DCHECK(IsSerialized()); + DCHECK(header_); + return static_cast<const MessageHeader*>(header_)->num_dispatchers; +} + +UserMessageImpl::UserMessageImpl(size_t event_size, + size_t header_size, + size_t payload_size, + size_t num_ports, + size_t num_handles) + : ports::UserMessage(&kUserMessageTypeInfo) { + const size_t size = event_size + header_size + payload_size; + void* data; + channel_message_ = NodeChannel::CreateEventMessage(size, &data, num_handles); + header_ = static_cast<uint8_t*>(data) + event_size; + user_payload_ = static_cast<uint8_t*>(header_) + header_size; + user_payload_size_ = payload_size; +} + +UserMessageImpl::UserMessageImpl(Channel::MessagePtr channel_message, + void* header, + void* user_payload, + size_t user_payload_size) + : ports::UserMessage(&kUserMessageTypeInfo), + channel_message_(std::move(channel_message)), + header_(header), + user_payload_(user_payload), + user_payload_size_(user_payload_size) {} + +} // namespace edk +} // namespace mojo
diff --git a/mojo/edk/system/user_message_impl.h b/mojo/edk/system/user_message_impl.h new file mode 100644 index 0000000..6699f9a --- /dev/null +++ b/mojo/edk/system/user_message_impl.h
@@ -0,0 +1,176 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_EDK_SYSTEM_USER_MESSAGE_IMPL_H_ +#define MOJO_EDK_SYSTEM_USER_MESSAGE_IMPL_H_ + +#include <memory> +#include <utility> + +#include "base/macros.h" +#include "mojo/edk/embedder/platform_handle_vector.h" +#include "mojo/edk/system/channel.h" +#include "mojo/edk/system/dispatcher.h" +#include "mojo/edk/system/ports/event.h" +#include "mojo/edk/system/ports/name.h" +#include "mojo/edk/system/ports/port_ref.h" +#include "mojo/edk/system/ports/user_message.h" +#include "mojo/edk/system/system_impl_export.h" +#include "mojo/public/c/system/message_pipe.h" +#include "mojo/public/c/system/types.h" + +namespace mojo { +namespace edk { + +class NodeController; + +// UserMessageImpl is the sole implementation of ports::UserMessage used to +// attach message data to any ports::UserMessageEvent. +// +// A UserMessageImpl may be either serialized or unserialized. Unserialized +// instances are serialized lazily only when necessary, i.e., if and when +// Serialize() is called to obtain a serialized message for wire transfer. +// +// TODO(crbug.com/725321): Implement support for unserialized messages. +class MOJO_SYSTEM_IMPL_EXPORT UserMessageImpl + : public NON_EXPORTED_BASE(ports::UserMessage) { + public: + static const TypeInfo kUserMessageTypeInfo; + + ~UserMessageImpl() override; + + // Creates a new ports::UserMessageEvent with an attached serialized + // UserMessageImpl. May fail iff one or more |dispatchers| fails to serialize + // (e.g. due to it being in an invalid state.) + // + // Upon success, MOJO_RESULT_OK is returned and the new UserMessageEvent is + // stored in |*out_event|. + static MojoResult CreateEventForNewSerializedMessage( + uint32_t num_bytes, + const Dispatcher::DispatcherInTransit* dispatchers, + uint32_t num_dispatchers, + std::unique_ptr<ports::UserMessageEvent>* out_event); + + // Creates a new UserMessageImpl from an existing serialized message buffer + // which was read from a Channel. Takes ownership of |channel_message|. + // |payload| and |payload_size| represent the range of bytes within + // |channel_message| which should be parsed by this call. + static std::unique_ptr<UserMessageImpl> CreateFromChannelMessage( + Channel::MessagePtr channel_message, + void* payload, + size_t payload_size); + + // Reads a message from |port| on |node_controller|'s Node. + // + // The message may or may not require deserialization. If the read message is + // unserialized, it must have been sent from within the same process that's + // receiving it and this call merely passes ownership of the message object + // back out of the ports layer. In this case, |read_any_size| must be true, + // |*out_event| will own the read message upon return, and all other arguments + // are ignored. + // + // If the read message is still serialized, it must have been created by + // CreateFromChannelMessage() above whenever its bytes were first read from a + // Channel. In this case, the message will be taken form the port and returned + // in |*out_event|, if and only iff |read_any_size| is true or both + // |*num_bytes| and |*num_handles| are sufficiently large to contain the + // contents of the message. Upon success this returns |MOJO_RESULT_OK|, and + // updates |*num_bytes| and |*num_handles| with the actual size of the read + // message. + // + // Upon failure this returns any of various error codes detailed by the + // documentation for MojoReadMessage/MojoReadMessageNew in + // src/mojo/public/c/system/message_pipe.h. + static MojoResult ReadMessageEventFromPort( + NodeController* node_controller, + const ports::PortRef& port, + bool read_any_size, + bool may_discard, + uint32_t* num_bytes, + MojoHandle* handles, + uint32_t* num_handles, + std::unique_ptr<ports::UserMessageEvent>* out_event); + + // Produces a serialized Channel::Message from the UserMessageEvent in + // |event|. |event| must have a UserMessageImpl instance attached. + // + // If the attached message is not already serialized, it is serialized into a + // new Channel::Message; otherwise this simply passes ownership of the + // internally owned serialized data. + // + // In any case, |message_event| is serialized into the front of the message + // payload before returning. + static Channel::MessagePtr SerializeEventMessage( + std::unique_ptr<ports::UserMessageEvent> event); + + // TODO(crbug.com/725321): Support unserialized messages. + bool HasContext() const { return false; } + uintptr_t context() const { return 0; } + bool IsSerialized() const { return true; } + + void* user_payload() { + DCHECK(IsSerialized()); + return user_payload_; + } + + const void* user_payload() const { + DCHECK(IsSerialized()); + return user_payload_; + } + + size_t user_payload_size() const { + DCHECK(IsSerialized()); + return user_payload_size_; + } + + size_t num_handles() const; + + void set_source_node(const ports::NodeName& name) { source_node_ = name; } + const ports::NodeName& source_node() const { return source_node_; } + + private: + class ReadMessageFilter; + + // Constructs a serialized UserMessageImpl backed by a new Channel::Message + // with enough storage for the given number of serialized event, header, and + // payload bytes; transferred ports; and system handles. + UserMessageImpl(size_t event_size, + size_t header_size, + size_t payload_size, + size_t num_ports, + size_t num_handles); + + // Creates a serialized UserMessageImpl backed by an existing Channel::Message + // object. |header| and |user_payload| must be pointers into + // |channel_message|'s own storage, and |user_payload_size| is the number of + // bytes comprising the user message contents at |user_payload|. + UserMessageImpl(Channel::MessagePtr channel_message, + void* header, + void* user_payload, + size_t user_payload_size); + + // Serialized message contents. May be null if this is not a serialized + // message. + Channel::MessagePtr channel_message_; + + // Only valid if |channel_message_| is non-null. |header_| is the address + // of the UserMessageImpl's internal MessageHeader structure within the + // serialized message buffer. |user_payload_| is the address of the first byte + // after any serialized dispatchers, with the payload comprising the remaining + // |user_payload_size_| bytes of the message. + void* header_ = nullptr; + void* user_payload_ = nullptr; + size_t user_payload_size_ = 0; + + // The node name from which this message was received, iff it came from + // out-of-process and the source is known. + ports::NodeName source_node_ = ports::kInvalidNodeName; + + DISALLOW_COPY_AND_ASSIGN(UserMessageImpl); +}; + +} // namespace edk +} // namespace mojo + +#endif // MOJO_EDK_SYSTEM_USER_MESSAGE_IMPL_H_
diff --git a/net/dns/dns_response.h b/net/dns/dns_response.h index 4d5e6b7..e9231a5d 100644 --- a/net/dns/dns_response.h +++ b/net/dns/dns_response.h
@@ -26,7 +26,8 @@ struct Header; } -// Parsed resource record. +// Structure representing a Resource Record as specified in RFC 1035, Section +// 4.1.3. struct NET_EXPORT_PRIVATE DnsResourceRecord { DnsResourceRecord(); ~DnsResourceRecord();
diff --git a/net/socket/tcp_client_socket.cc b/net/socket/tcp_client_socket.cc index 9e1470ff..df07d11 100644 --- a/net/socket/tcp_client_socket.cc +++ b/net/socket/tcp_client_socket.cc
@@ -151,32 +151,26 @@ const IPEndPoint& endpoint = addresses_[current_address_index_]; - { - // TODO(ricea): Remove ScopedTracker below once crbug.com/436634 is fixed. - tracked_objects::ScopedTracker tracking_profile( - FROM_HERE_WITH_EXPLICIT_FUNCTION("436634 TCPClientSocket::DoConnect")); + if (previously_disconnected_) { + use_history_.Reset(); + connection_attempts_.clear(); + previously_disconnected_ = false; + } - if (previously_disconnected_) { - use_history_.Reset(); - connection_attempts_.clear(); - previously_disconnected_ = false; - } + next_connect_state_ = CONNECT_STATE_CONNECT_COMPLETE; - next_connect_state_ = CONNECT_STATE_CONNECT_COMPLETE; + if (socket_->IsValid()) { + DCHECK(bind_address_); + } else { + int result = OpenSocket(endpoint.GetFamily()); + if (result != OK) + return result; - if (socket_->IsValid()) { - DCHECK(bind_address_); - } else { - int result = OpenSocket(endpoint.GetFamily()); - if (result != OK) + if (bind_address_) { + result = socket_->Bind(*bind_address_); + if (result != OK) { + socket_->Close(); return result; - - if (bind_address_) { - result = socket_->Bind(*bind_address_); - if (result != OK) { - socket_->Close(); - return result; - } } } }
diff --git a/net/socket/tcp_socket_win.cc b/net/socket/tcp_socket_win.cc index 7b4072e..fc85d800 100644 --- a/net/socket/tcp_socket_win.cc +++ b/net/socket/tcp_socket_win.cc
@@ -815,17 +815,7 @@ if (!peer_address_->ToSockAddr(storage.addr, &storage.addr_len)) return ERR_ADDRESS_INVALID; - int result; - int os_error; - { - // TODO(ricea): Remove ScopedTracker below once crbug.com/436634 is fixed. - tracked_objects::ScopedTracker tracking_profile( - FROM_HERE_WITH_EXPLICIT_FUNCTION("436634 connect()")); - result = connect(socket_, storage.addr, storage.addr_len); - os_error = WSAGetLastError(); - } - - if (!result) { + if (!connect(socket_, storage.addr, storage.addr_len)) { // Connected without waiting! // // The MSDN page for connect says: @@ -841,6 +831,7 @@ if (ResetEventIfSignaled(core_->read_overlapped_.hEvent)) return OK; } else { + int os_error = WSAGetLastError(); if (os_error != WSAEWOULDBLOCK) { LOG(ERROR) << "connect failed: " << os_error; connect_os_error_ = os_error; @@ -850,10 +841,6 @@ } } - // TODO(ricea): Remove ScopedTracker below once crbug.com/436634 is fixed. - tracked_objects::ScopedTracker tracking_profile( - FROM_HERE_WITH_EXPLICIT_FUNCTION("436634 WatchForRead()")); - core_->WatchForRead(); return ERR_IO_PENDING; }
diff --git a/net/socket/transport_client_socket_pool.cc b/net/socket/transport_client_socket_pool.cc index c0279e1..003390a 100644 --- a/net/socket/transport_client_socket_pool.cc +++ b/net/socket/transport_client_socket_pool.cc
@@ -254,11 +254,6 @@ return rv; } int TransportConnectJob::DoResolveHost() { - // TODO(ricea): Remove ScopedTracker below once crbug.com/436634 is fixed. - tracked_objects::ScopedTracker tracking_profile( - FROM_HERE_WITH_EXPLICIT_FUNCTION( - "436634 TransportConnectJob::DoResolveHost")); - next_state_ = STATE_RESOLVE_HOST_COMPLETE; connect_timing_.dns_start = base::TimeTicks::Now();
diff --git a/remoting/webapp/base/js/client_plugin_impl.js b/remoting/webapp/base/js/client_plugin_impl.js index ae72b7e..8ba6065 100644 --- a/remoting/webapp/base/js/client_plugin_impl.js +++ b/remoting/webapp/base/js/client_plugin_impl.js
@@ -278,10 +278,16 @@ base.getNumberAttr(message.data, 'videoBandwidth'); base.getNumberAttr(message.data, 'videoFrameRate'); base.getNumberAttr(message.data, 'captureLatency'); + base.getNumberAttr(message.data, 'maxCaptureLatency'); base.getNumberAttr(message.data, 'encodeLatency'); + base.getNumberAttr(message.data, 'maxEncodeLatency'); base.getNumberAttr(message.data, 'decodeLatency'); + base.getNumberAttr(message.data, 'maxDecodeLatency'); base.getNumberAttr(message.data, 'renderLatency'); + base.getNumberAttr(message.data, 'maxRenderLatency'); base.getNumberAttr(message.data, 'roundtripLatency'); + base.getNumberAttr(message.data, 'maxRoundtripLatency'); + this.perfStats_ = /** @type {remoting.ClientSession.PerfStats} */ (message.data);
diff --git a/remoting/webapp/base/js/client_session.js b/remoting/webapp/base/js/client_session.js index 8d02310..9bafa76 100644 --- a/remoting/webapp/base/js/client_session.js +++ b/remoting/webapp/base/js/client_session.js
@@ -228,6 +228,20 @@ /** @type {number} */ remoting.ClientSession.PerfStats.prototype.maxRoundtripLatency = 0; +/** + * @param {!remoting.ClientSession.PerfStats} stats + * @return {boolean} true if there is any non-zero value in stats, false + * otherwise. + */ +remoting.ClientSession.PerfStats.hasValidField = function(stats) { + for (var key in stats) { + if (stats[key] !== 0) { + return true; + } + } + return false; +} + // Keys for connection statistics. remoting.ClientSession.STATS_KEY_VIDEO_BANDWIDTH = 'videoBandwidth'; remoting.ClientSession.STATS_KEY_VIDEO_FRAME_RATE = 'videoFrameRate'; @@ -561,7 +575,7 @@ if (newState == remoting.ClientSession.State.CONNECTED) { this.connectedDisposables_.add( - new base.RepeatingTimer(this.reportStatistics.bind(this), 1000)); + new base.RepeatingTimer(this.reportStatistics.bind(this), 1000 * 60)); if (this.plugin_.hasCapability( remoting.ClientSession.Capability.TOUCH_EVENTS)) { this.plugin_.enableTouchEvents(true);
diff --git a/remoting/webapp/base/js/session_logger.js b/remoting/webapp/base/js/session_logger.js index 616b663..e2a34561 100644 --- a/remoting/webapp/base/js/session_logger.js +++ b/remoting/webapp/base/js/session_logger.js
@@ -25,8 +25,6 @@ /** @private */ this.writeLogEntry_ = writeLogEntry; /** @private */ - this.statsAccumulator_ = new remoting.StatsAccumulator(); - /** @private */ this.sessionId_ = ''; /** @private */ this.sessionIdGenerationTime_ = 0; @@ -235,11 +233,7 @@ this.sessionEndTime_ = Date.now(); } - // Don't accumulate connection statistics across state changes. - this.logAccumulatedStatistics_(); - this.statsAccumulator_.empty(); - - if (state == remoting.ChromotingEvent.SessionState.CLOSED || + if (state == remoting.ChromotingEvent.SessionState.CLOSED || state == remoting.ChromotingEvent.SessionState.CONNECTION_DROPPED) { this.flushFeatureTracker(); } @@ -248,17 +242,13 @@ /** * Logs connection statistics. * - * @param {Object<number>} stats The connection statistics + * @param {remoting.ClientSession.PerfStats} stats The connection statistics */ remoting.SessionLogger.prototype.logStatistics = function(stats) { - this.maybeExpireSessionId_(); - // Store the statistics. - this.statsAccumulator_.add(stats); - // Send statistics to the server if they've been accumulating for at least - // 60 seconds. - if (this.statsAccumulator_.getTimeSinceFirstValue() >= - remoting.SessionLogger.CONNECTION_STATS_ACCUMULATE_TIME) { - this.logAccumulatedStatistics_(); + if (stats && remoting.ClientSession.PerfStats.hasValidField(stats)) { + this.maybeExpireSessionId_(); + var entry = this.makeStats_(stats); + this.log_(entry); } }; @@ -266,7 +256,9 @@ * Logs host and client dimensions. * * @param {{width: number, height: number}} hostSize + * @param {number} hostDpi * @param {{width: number, height: number}} clientPluginSize + * @param {number} clientDpi * @param {{width: number, height: number}} clientWindowSize * @param {boolean} clientFullscreen */ @@ -309,8 +301,10 @@ /** * @param {{width: number, height: number}} hostSize + * @param {number} hostDpi * @param {{width: number, height: number}} clientPluginSize * @param {{width: number, height: number}} clientWindowSize + * @param {number} clientDpi * @param {boolean} clientFullscreen * @return {remoting.ChromotingEvent} * @private @@ -354,46 +348,28 @@ }; /** - * @return {remoting.ChromotingEvent} + * @param {!remoting.ClientSession.PerfStats} perfStats + * @return {!remoting.ChromotingEvent} * @private */ -remoting.SessionLogger.prototype.makeStats_ = function() { - var perfStats = this.statsAccumulator_.getPerfStats(); - if (Boolean(perfStats)) { - var entry = new remoting.ChromotingEvent( - remoting.ChromotingEvent.Type.CONNECTION_STATISTICS); - this.fillEvent_(entry); - entry.video_bandwidth = perfStats.videoBandwidth; - entry.capture_latency = perfStats.captureLatency; - entry.encode_latency = perfStats.encodeLatency; - entry.decode_latency = perfStats.decodeLatency; - entry.render_latency = perfStats.renderLatency; - entry.roundtrip_latency = perfStats.roundtripLatency; - entry.max_capture_latency = perfStats.maxCaptureLatency; - entry.max_encode_latency = perfStats.maxEncodeLatency; - entry.max_decode_latency = perfStats.maxDecodeLatency; - entry.max_render_latency = perfStats.maxRenderLatency; - entry.max_roundtrip_latency = perfStats.maxRoundtripLatency; - return entry; - } - return null; +remoting.SessionLogger.prototype.makeStats_ = function(perfStats) { + var entry = new remoting.ChromotingEvent( + remoting.ChromotingEvent.Type.CONNECTION_STATISTICS); + this.fillEvent_(entry); + entry.video_bandwidth = perfStats.videoBandwidth; + entry.capture_latency = perfStats.captureLatency; + entry.encode_latency = perfStats.encodeLatency; + entry.decode_latency = perfStats.decodeLatency; + entry.render_latency = perfStats.renderLatency; + entry.roundtrip_latency = perfStats.roundtripLatency; + entry.max_capture_latency = perfStats.maxCaptureLatency; + entry.max_encode_latency = perfStats.maxEncodeLatency; + entry.max_decode_latency = perfStats.maxDecodeLatency; + entry.max_render_latency = perfStats.maxRenderLatency; + entry.max_roundtrip_latency = perfStats.maxRoundtripLatency; + return entry; }; -/** - * Moves connection statistics from the accumulator to the log server. - * - * If all the statistics are zero, then the accumulator is still emptied, - * but the statistics are not sent to the log server. - * - * @private - */ -remoting.SessionLogger.prototype.logAccumulatedStatistics_ = function() { - var entry = this.makeStats_(); - if (entry) { - this.log_(entry); - } - this.statsAccumulator_.empty(); -}; /** * @param {remoting.ChromotingEvent} entry @@ -558,8 +534,4 @@ // The maximum age of a session ID, in milliseconds. remoting.SessionLogger.MAX_SESSION_ID_AGE = 24 * 60 * 60 * 1000; -// The time over which to accumulate connection statistics before logging them -// to the server, in milliseconds. -remoting.SessionLogger.CONNECTION_STATS_ACCUMULATE_TIME = 60 * 1000; - })();
diff --git a/remoting/webapp/base/js/session_logger_unittest.js b/remoting/webapp/base/js/session_logger_unittest.js index 460dec5..c1d55b45 100644 --- a/remoting/webapp/base/js/session_logger_unittest.js +++ b/remoting/webapp/base/js/session_logger_unittest.js
@@ -277,36 +277,19 @@ logger.setConnectionType('direct'); logger.setHost(fakeHost); - // Log the statistics. - logger.logStatistics({ - videoBandwidth: 1.0, - captureLatency: 1.0, - encodeLatency: 1.0, - decodeLatency: 0.0, - renderLatency: 1.0, - roundtripLatency: 1.0 - }); - - logger.logStatistics({ - videoBandwidth: 2.0, - captureLatency: 2.0, - encodeLatency: 1.0, - decodeLatency: 0.0, - renderLatency: 2.0, - roundtripLatency: 2.0 - }); - - sinon.assert.notCalled(logWriterSpy); - // Stats should only be accumulated at |CONNECTION_STATS_ACCUMULATE_TIME|. - clock.tick(remoting.SessionLogger.CONNECTION_STATS_ACCUMULATE_TIME + 10); - + // Log the statistics logger.logStatistics({ videoBandwidth: 3.0, - captureLatency: 3.0, - encodeLatency: 1.0, - decodeLatency: 0.0, - renderLatency: 0.0, - roundtripLatency: 0.0 + captureLatency: 1.0, + maxCaptureLatency: 3.0, + encodeLatency: 2.0, + maxEncodeLatency: 4.0, + decodeLatency: 3.0, + maxDecodeLatency: 5.0, + renderLatency: 4.0, + maxRenderLatency: 6.0, + roundtripLatency: 5.0, + maxRoundtripLatency: 7.0 }); verifyEvent(assert, 0, { @@ -323,12 +306,17 @@ host_os: remoting.ChromotingEvent.Os.OTHER, host_os_version: 'host_os_version', session_id: logger.getSessionId(), - video_bandwidth: 2.0, - capture_latency: 2.0, - encode_latency: 1.0, - decode_latency: 0.0, - render_latency: 1.0, - roundtrip_latency: 1.0 + video_bandwidth: 3.0, + capture_latency: 1.0, + encode_latency: 2.0, + decode_latency: 3.0, + render_latency: 4.0, + roundtrip_latency: 5.0, + max_capture_latency: 3.0, + max_encode_latency: 4.0, + max_decode_latency: 5.0, + max_render_latency: 6.0, + max_roundtrip_latency: 7.0 }); }); @@ -349,17 +337,6 @@ roundtripLatency: 0.0 }); - clock.tick(remoting.SessionLogger.CONNECTION_STATS_ACCUMULATE_TIME + 10); - - logger.logStatistics({ - videoBandwidth: 0.0, - captureLatency: 0.0, - encodeLatency: 0.0, - decodeLatency: 0.0, - renderLatency: 0.0, - roundtripLatency: 0.0 - }); - sinon.assert.notCalled(logWriterSpy); });
diff --git a/remoting/webapp/base/js/stats_accumulator.js b/remoting/webapp/base/js/stats_accumulator.js deleted file mode 100644 index 8d4cb6b..0000000 --- a/remoting/webapp/base/js/stats_accumulator.js +++ /dev/null
@@ -1,186 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @fileoverview - * The webapp reads the plugin's connection statistics frequently (once per - * second). It logs statistics to the server less frequently, to keep - * bandwidth and storage costs down. This class bridges that gap, by - * accumulating high-frequency numeric data, and providing statistics - * summarising that data. - */ - -'use strict'; - -/** @suppress {duplicate} */ -var remoting = remoting || {}; - -(function() { - -/** - * @constructor - */ -remoting.StatsAccumulator = function() { - /** - * A map from names to lists of values. - * @private {Object<Array<number>>} - */ - this.valueLists_ = {}; - - /** - * The first time, after this object was most recently initialized or emptied, - * at which a value was added to this object. - * @private {?number} - */ - this.timeOfFirstValue_ = null; -}; - -/** - * @param {Object<number>} stats - * @return {boolean} true if there is any non-zero value in stats, false - * otherwise. - */ -function hasValidField(stats) { - for (var key in stats) { - if (stats[key] !== 0) { - return true; - } - } - return false; -} - -/** - * Adds values to this object. Do nothing if newValues has no valid field. - * - * @param {Object<number>} newValues - */ -remoting.StatsAccumulator.prototype.add = function(newValues) { - if (!hasValidField(newValues)) { - return; - } - for (var key in newValues) { - this.getValueList(key).push(newValues[key]); - } - if (this.timeOfFirstValue_ === null) { - this.timeOfFirstValue_ = new Date().getTime(); - } -}; - -/** - * Empties this object. - */ -remoting.StatsAccumulator.prototype.empty = function() { - this.valueLists_ = {}; - this.timeOfFirstValue_ = null; -}; - -/** - * Gets the number of milliseconds since the first value was added to this - * object, after this object was most recently initialized or emptied. - * - * @return {number} milliseconds since the first value - */ -remoting.StatsAccumulator.prototype.getTimeSinceFirstValue = function() { - if (this.timeOfFirstValue_ === null) { - return 0; - } - return new Date().getTime() - this.timeOfFirstValue_; -}; - -/** - * Calculates the mean of the values for a given key. - * - * @param {string} key - * @return {number} the mean of the values for that key - */ -remoting.StatsAccumulator.prototype.calcMean = function(key) { - /** - * @param {Array<number>} values - * @return {number} - */ - var calcMean = function(values) { - if (values.length == 0) { - return 0.0; - } - var sum = 0; - for (var i = 0; i < values.length; i++) { - sum += values[i]; - } - return sum / values.length; - }; - return this.map(key, calcMean); -}; - -/** - * Finds the max of the values for a given key. - * - * @param {string} key - * @return {number} the max of the values for that key - */ -remoting.StatsAccumulator.prototype.calcMax = function(key) { - /** - * @param {Array<number>} values - * @return {number} - */ - var calcMax = function(values) { - if (!values || !values.length) { - return 0; - } - return Math.max.apply(null, values); - }; - return this.map(key, calcMax); -}; - -/** - * Applies a given map to the list of values for a given key. - * - * @param {string} key - * @param {function(Array<number>): number} map - * @return {number} the result of applying that map to the list of values for - * that key - */ -remoting.StatsAccumulator.prototype.map = function(key, map) { - return map(this.getValueList(key)); -}; - -/** - * Gets the list of values for a given key. - * If this object contains no values for that key, then this routine creates - * an empty list, stores it in this object, and returns it. - * - * @private - * @param {string} key - * @return {Array<number>} the list of values for that key - */ -remoting.StatsAccumulator.prototype.getValueList = function(key) { - var valueList = this.valueLists_[key]; - if (!valueList) { - valueList = []; - this.valueLists_[key] = valueList; - } - return valueList; -}; - -/** - * @return {?remoting.ClientSession.PerfStats} returns null if all fields are - * zero. - */ -remoting.StatsAccumulator.prototype.getPerfStats = function() { - var stats = new remoting.ClientSession.PerfStats(); - stats.videoBandwidth = this.calcMean('videoBandwidth'); - stats.captureLatency = this.calcMean('captureLatency'); - stats.maxCaptureLatency = this.calcMax('maxCaptureLatency'); - stats.encodeLatency = this.calcMean('encodeLatency'); - stats.maxEncodeLatency = this.calcMax('maxEncodeLatency'); - stats.decodeLatency = this.calcMean('decodeLatency'); - stats.maxDecodeLatency = this.calcMax('maxDecodeLatency'); - stats.renderLatency = this.calcMean('renderLatency'); - stats.maxRenderLatency = this.calcMax('maxRenderLatency'); - stats.roundtripLatency = this.calcMean('roundtripLatency'); - stats.maxRoundtripLatency = this.calcMax('maxRoundtripLatency'); - - return hasValidField(stats) ? stats : null; -}; - -})(); \ No newline at end of file
diff --git a/remoting/webapp/build_template.gni b/remoting/webapp/build_template.gni index e3c0339..28b4c91 100644 --- a/remoting/webapp/build_template.gni +++ b/remoting/webapp/build_template.gni
@@ -83,7 +83,7 @@ "--out_file", rebase_path(target_jscompile_stamp, root_build_dir), "--closure_args", - ] + closure_args + extra_closure_args + ] + default_closure_args + extra_closure_args args += [ "--externs" ] + rebase_path(externs, root_build_dir) } }
diff --git a/remoting/webapp/files.gni b/remoting/webapp/files.gni index f32fbad..2dfd7428 100644 --- a/remoting/webapp/files.gni +++ b/remoting/webapp/files.gni
@@ -207,7 +207,6 @@ remoting_webapp_shared_js_logging_files = [ "base/js/format_iq.js", "base/js/session_logger.js", - "base/js/stats_accumulator.js", ] # Remoting signaling files.
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json index e9c3b38..61df261 100644 --- a/testing/buildbot/chromium.linux.json +++ b/testing/buildbot/chromium.linux.json
@@ -161,7 +161,7 @@ ], "dimension_sets": [ { - "android_devices": "4", + "android_devices": "1", "device_os": "KTU84P", "device_type": "hammerhead" } @@ -624,7 +624,7 @@ ], "dimension_sets": [ { - "android_devices": "4", + "android_devices": "1", "device_os": "KTU84P", "device_type": "hammerhead" } @@ -663,7 +663,7 @@ ], "dimension_sets": [ { - "android_devices": "4", + "android_devices": "1", "device_os": "KTU84P", "device_type": "hammerhead" } @@ -702,7 +702,7 @@ ], "dimension_sets": [ { - "android_devices": "4", + "android_devices": "1", "device_os": "KTU84P", "device_type": "hammerhead" } @@ -781,7 +781,7 @@ ], "dimension_sets": [ { - "android_devices": "4", + "android_devices": "1", "device_os": "KTU84P", "device_type": "hammerhead" } @@ -889,7 +889,7 @@ ], "dimension_sets": [ { - "android_devices": "4", + "android_devices": "1", "device_os": "KTU84P", "device_type": "hammerhead" } @@ -1007,7 +1007,7 @@ ], "dimension_sets": [ { - "android_devices": "4", + "android_devices": "1", "device_os": "KTU84P", "device_type": "hammerhead" } @@ -1047,7 +1047,7 @@ ], "dimension_sets": [ { - "android_devices": "4", + "android_devices": "1", "device_os": "KTU84P", "device_type": "hammerhead" } @@ -1323,7 +1323,7 @@ ], "dimension_sets": [ { - "android_devices": "4", + "android_devices": "1", "device_os": "KTU84P", "device_type": "hammerhead" } @@ -1362,7 +1362,7 @@ ], "dimension_sets": [ { - "android_devices": "4", + "android_devices": "1", "device_os": "KTU84P", "device_type": "hammerhead" } @@ -1401,7 +1401,7 @@ ], "dimension_sets": [ { - "android_devices": "4", + "android_devices": "1", "device_os": "KTU84P", "device_type": "hammerhead" } @@ -1714,7 +1714,7 @@ ], "dimension_sets": [ { - "android_devices": "4", + "android_devices": "1", "device_os": "KTU84P", "device_type": "hammerhead" } @@ -2177,7 +2177,7 @@ ], "dimension_sets": [ { - "android_devices": "4", + "android_devices": "1", "device_os": "KTU84P", "device_type": "hammerhead" } @@ -2216,7 +2216,7 @@ ], "dimension_sets": [ { - "android_devices": "4", + "android_devices": "1", "device_os": "KTU84P", "device_type": "hammerhead" } @@ -2255,7 +2255,7 @@ ], "dimension_sets": [ { - "android_devices": "4", + "android_devices": "1", "device_os": "KTU84P", "device_type": "hammerhead" } @@ -2334,7 +2334,7 @@ ], "dimension_sets": [ { - "android_devices": "4", + "android_devices": "1", "device_os": "KTU84P", "device_type": "hammerhead" } @@ -2442,7 +2442,7 @@ ], "dimension_sets": [ { - "android_devices": "4", + "android_devices": "1", "device_os": "KTU84P", "device_type": "hammerhead" } @@ -2560,7 +2560,7 @@ ], "dimension_sets": [ { - "android_devices": "4", + "android_devices": "1", "device_os": "KTU84P", "device_type": "hammerhead" } @@ -2600,7 +2600,7 @@ ], "dimension_sets": [ { - "android_devices": "4", + "android_devices": "1", "device_os": "KTU84P", "device_type": "hammerhead" } @@ -2907,7 +2907,7 @@ ], "dimension_sets": [ { - "android_devices": "4", + "android_devices": "1", "device_os": "KTU84P", "device_type": "hammerhead" } @@ -2946,7 +2946,7 @@ ], "dimension_sets": [ { - "android_devices": "4", + "android_devices": "1", "device_os": "KTU84P", "device_type": "hammerhead" } @@ -2985,7 +2985,7 @@ ], "dimension_sets": [ { - "android_devices": "4", + "android_devices": "1", "device_os": "KTU84P", "device_type": "hammerhead" }
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index f723435..0f8714a 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -2915,6 +2915,26 @@ ] } ], + "SocketReadIfReady": [ + { + "platforms": [ + "android", + "chromeos", + "linux", + "mac", + "ios", + "win" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "SocketReadIfReady" + ] + } + ] + } + ], "SpeculativeLaunchServiceWorker": [ { "platforms": [
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 936d1f2..096bd59 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2016,6 +2016,13 @@ crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/crossorigin.html [ Failure ] crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/errorhandling.html [ Failure ] crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/imports.html [ Failure ] +crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/compilation-error-1.html [ Failure ] +crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/compilation-error-2.html [ Failure ] +crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/evaluation-error-1.html [ Failure ] +crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/evaluation-error-2.html [ Failure ] +crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/evaluation-error-3.html [ Failure ] +crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/evaluation-error-4.html [ Failure ] +crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/specifier-error.html [ Failure ] # This test has a failure console message with specific performance # numbers so a consistent baseline cannot be added. This test could be
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/bad-module-specifier.js b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/bad-module-specifier.js new file mode 100644 index 0000000..a53a3beb --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/bad-module-specifier.js
@@ -0,0 +1,3 @@ +import "string-without-dot-slash-prefix"; +import "./this.js"; +log.push("bad-module-specifier");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/compilation-error-1.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/compilation-error-1.html new file mode 100644 index 0000000..ff580d48 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/compilation-error-1.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<title>Handling of compilation errors, 1</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + + const test_load = async_test( + "Test that syntax errors lead to SyntaxError events on window, " + + "and that exceptions are remembered."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_equals(log.length, 5); + assert_equals(log[0].constructor, SyntaxError); + assert_true(log.every(exn => exn === log[0])); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./syntaxerror.js" onerror="unreachable()"></script> +<script type="module" src="./syntaxerror.js" onerror="unreachable()"></script> +<script type="module" src="./syntaxerror-nested.js" onerror="unreachable()"></script> +<script type="module" src="./syntaxerror.js" onerror="unreachable()"></script> +<script type="module" src="./syntaxerror-nested.js" onerror="unreachable()"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/compilation-error-2.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/compilation-error-2.html new file mode 100644 index 0000000..131a6e4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/compilation-error-2.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<title>Handling of compilation errors, 2</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + + const test_load = async_test( + "Test that syntax errors lead to SyntaxError events on window, " + + "and that exceptions are remembered."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_equals(log.length, 5); + assert_equals(log[0].constructor, SyntaxError); + assert_true(log.every(exn => exn === log[0])); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./syntaxerror-nested.js" onerror="unreachable()"></script> +<script type="module" src="./syntaxerror-nested.js" onerror="unreachable()"></script> +<script type="module" src="./syntaxerror.js" onerror="unreachable()"></script> +<script type="module" src="./syntaxerror-nested.js" onerror="unreachable()"></script> +<script type="module" src="./syntaxerror.js" onerror="unreachable()"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/cycle-tdz-access-a.js b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/cycle-tdz-access-a.js new file mode 100644 index 0000000..1f91f93 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/cycle-tdz-access-a.js
@@ -0,0 +1,3 @@ +log.push("cycle-tdz-access-a"); +import { Y } from "./cycle-tdz-access.js"; +export var X = Y;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/cycle-tdz-access.js b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/cycle-tdz-access.js new file mode 100644 index 0000000..9df68b3 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/cycle-tdz-access.js
@@ -0,0 +1,3 @@ +log.push("cycle-tdz-access"); +import { X } from "./cycle-tdz-access-a.js"; +export let Y = X;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/cycle-unresolvable-a.js b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/cycle-unresolvable-a.js new file mode 100644 index 0000000..12994f2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/cycle-unresolvable-a.js
@@ -0,0 +1,2 @@ +export {x} from "./cycle-unresolvable.js"; +log.push("cycle-unresolvable-a");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/cycle-unresolvable.js b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/cycle-unresolvable.js new file mode 100644 index 0000000..61c6d8d --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/cycle-unresolvable.js
@@ -0,0 +1,2 @@ +export {x} from "./cycle-unresolvable-a.js"; +log.push("cycle-unresolvable");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/evaluation-error-1.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/evaluation-error-1.html new file mode 100644 index 0000000..21f005a --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/evaluation-error-1.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<title>Handling of evaluation errors, 1</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + + const test_load = async_test( + "Test that exceptions during evaluation lead to error events on " + + "window, and that exceptions are remembered.\n"); + window.addEventListener("load", test_load.step_func_done(ev => { + const exn = log[1]; + assert_array_equals(log, ["throw", exn, exn, exn, exn]); + assert_true(exn.foo); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="throw.js" onerror="unreachable()"></script> +<script type="module" src="throw.js" onerror="unreachable()"></script> +<script type="module" src="throw.js" async onerror="unreachable()"></script> +<script type="module" src="throw.js" nomodule onerror="unreachable()"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/evaluation-error-2.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/evaluation-error-2.html new file mode 100644 index 0000000..6aedc060 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/evaluation-error-2.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<title>Handling of evaluation errors, 2</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + + const test_load = async_test( + "Test that ill-founded cyclic dependencies cause ReferenceError " + + "during evaluation, which leads to error events on window, and that " + + "exceptions are remembered.\n"); + window.addEventListener("load", test_load.step_func_done(ev => { + const exn = log[1]; + assert_array_equals(log, ["cycle-tdz-access-a", exn, exn, exn]); + assert_equals(exn.constructor, ReferenceError); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="cycle-tdz-access.js" async onerror="unreachable()"></script> +<script type="module" src="cycle-tdz-access.js" nomodule onerror="unreachable()"></script> +<script type="module" src="cycle-tdz-access.js" onerror="unreachable()"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/evaluation-error-3.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/evaluation-error-3.html new file mode 100644 index 0000000..71d61f5a --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/evaluation-error-3.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<title>Handling of evaluation errors, 3</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + + const test_load = async_test( + "Test that exceptions during evaluation lead to error events on " + + "window, and that exceptions are remembered.\n"); + window.addEventListener("load", test_load.step_func_done(ev => { + const exn = log[1]; + assert_array_equals(log, ["throw", exn, exn, exn, exn, exn]); + assert_true(exn.foo); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./throw.js" onerror="unreachable()"></script> +<script type="module" src="./throw.js" onerror="unreachable()"></script> +<script type="module" src="./throw-nested.js" onerror="unreachable()"></script> +<script type="module" src="./throw.js" onerror="unreachable()"></script> +<script type="module" src="./throw-nested.js" onerror="unreachable()"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/evaluation-error-4.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/evaluation-error-4.html new file mode 100644 index 0000000..dcb0108 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/evaluation-error-4.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<title>Handling of evaluation errors, 4</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + + const test_load = async_test( + "Test that exceptions during evaluation lead to error events on " + + "window, and that exceptions are remembered.\n"); + window.addEventListener("load", test_load.step_func_done(ev => { + const exn = log[1]; + assert_array_equals(log, ["throw", exn, exn, exn, exn, exn]); + assert_true(exn.foo); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./throw-nested.js" onerror="unreachable()"></script> +<script type="module" src="./throw-nested.js" onerror="unreachable()"></script> +<script type="module" src="./throw.js" onerror="unreachable()"></script> +<script type="module" src="./throw-nested.js" onerror="unreachable()"></script> +<script type="module" src="./throw.js" onerror="unreachable()"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/export-something-nested.js b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/export-something-nested.js new file mode 100644 index 0000000..ca806eb --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/export-something-nested.js
@@ -0,0 +1,2 @@ +log.push("export-something-nested"); +export * from "./export-something.js";
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/export-something.js b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/export-something.js new file mode 100644 index 0000000..cf2c3a99 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/export-something.js
@@ -0,0 +1,3 @@ +log.push("export-something"); +export let foo = 42; +export function set_foo(x) { foo = x };
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/fetch-error-1.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/fetch-error-1.html new file mode 100644 index 0000000..170bb665 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/fetch-error-1.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<title>Handling of fetch errors, 1</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + window.log = []; + + const test_load = async_test( + "Test that failure to fetch root leads to error event on script."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_array_equals(log, ["script"]); + })); +</script> +<script type="module" src="./no-such-file.js" onerror="log.push('script')"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/fetch-error-2.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/fetch-error-2.html new file mode 100644 index 0000000..9386ce6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/fetch-error-2.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<title>Handling of fetch errors, 2</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + window.log = []; + + const test_load = async_test( + "Test that failure to fetch dependency leads to error event on script."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_array_equals(log, ["script"]); + })); +</script> +<script type="module" src="./fetch-error-2.js" onerror="log.push('script')"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/fetch-error-2.js b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/fetch-error-2.js new file mode 100644 index 0000000..20c0ea6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/fetch-error-2.js
@@ -0,0 +1,2 @@ +import "./no-such-file.js" +import "./this.js";
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/import-something-namespace.js b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/import-something-namespace.js new file mode 100644 index 0000000..32d90287 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/import-something-namespace.js
@@ -0,0 +1,5 @@ +log.push("import-something-namespace"); +log.push(m.foo); +m.set_foo(43); +log.push(m.foo); +import * as m from "./export-something.js";
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html index a9556b1a..efdf587 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html
@@ -1,22 +1,33 @@ -<!-- -This test case caught a crash bug in Chrome, due to a logic bug in the spec when -a second <script> element tried to load a previously-failed module. As such, the -test passes as long as nothing crashes. - -See https://github.com/whatwg/html/pull/2559 for background. ---> - <!DOCTYPE html> -<html> -<head> - <title>html-script-module-instantiation-error-1</title> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> -</head> -<body> - <h1>html-script-module-instantiation-error-1</h1> - <script> setup({allow_uncaught_exception: true}) </script> - <script type="module" src="./instantiation-error-1.js"></script> - <script type="module" src="./instantiation-error-1.js"></script> -</body> -</html> +<title>Handling of instantiation errors, 1</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + + const test_load = async_test( + "Test that missing exports lead to SyntaxError events on window and " + + "load events on script, and that exceptions are remembered"); + window.addEventListener("load", test_load.step_func_done(ev => { + const exn = log[0]; + assert_array_equals(log, [exn, 1, exn, 2, exn, 3, exn, 4, exn, 5]); + assert_equals(exn.constructor, SyntaxError); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./missing-export.js" + onerror="unreachable()" onload="log.push(1)"></script> +<script type="module" src="./missing-export.js" + onerror="unreachable()" onload="log.push(2)"></script> +<script type="module" src="./missing-export-nested.js" + onerror="unreachable()" onload="log.push(3)"></script> +<script type="module" src="./missing-export.js" + onerror="unreachable()" onload="log.push(4)"></script> +<script type="module" src="./missing-export-nested.js" + onerror="unreachable()" onload="log.push(5)"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html new file mode 100644 index 0000000..3d50ce6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html
@@ -0,0 +1,33 @@ +<!DOCTYPE html> +<title>Handling of instantiation errors, 2</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + + const test_load = async_test( + "Test that missing exports lead to SyntaxError events on window and " + + "load events on script, and that exceptions are remembered"); + window.addEventListener("load", test_load.step_func_done(ev => { + const exn = log[0]; + assert_array_equals(log, [exn, 1, exn, 2, exn, 3, exn, 4, exn, 5]); + assert_equals(exn.constructor, SyntaxError); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./missing-export-nested.js" + onerror="unreachable()" onload="log.push(1)"></script> +<script type="module" src="./missing-export-nested.js" + onerror="unreachable()" onload="log.push(2)"></script> +<script type="module" src="./missing-export.js" + onerror="unreachable()" onload="log.push(3)"></script> +<script type="module" src="./missing-export-nested.js" + onerror="unreachable()" onload="log.push(4)"></script> +<script type="module" src="./missing-export.js" + onerror="unreachable()" onload="log.push(5)"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html new file mode 100644 index 0000000..ab510c675 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<title>Handling of instantiation errors, 3</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + + const test_load = async_test( + "Test that unresolvable cycles lead to SyntaxError events on window " + + "and load events on script, and that exceptions are remembered"); + window.addEventListener("load", test_load.step_func_done(ev => { + const exn = log[0]; + assert_array_equals(log, [exn, 1, exn, 2, exn, 3]); + assert_equals(exn.constructor, SyntaxError); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./cycle-unresolvable.js" + onerror="unreachable()" onload="log.push(1)" nomodule></script> +<script type="module" src="./cycle-unresolvable-a.js" + onerror="unreachable()" onload="log.push(2)"></script> +<script type="module" src="./cycle-unresolvable.js" + onerror="unreachable()" onload="log.push(3)" async></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/late-namespace-request.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/late-namespace-request.html new file mode 100644 index 0000000..00269ef --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/late-namespace-request.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<title>Late namespace request</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + window.log = []; + + const test_load = async_test( + "Test the situation where a module is instantiated without the " + + "need for a namespace object, but later on a different module " + + "requests the namespace."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_array_equals(log, + ["export-something", + "import-something-namespace", 42, 43]); + })); +</script> +<script type="module" src="export-something.js"></script> +<script type="module" src="import-something-namespace.js"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/late-star-export-request.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/late-star-export-request.html new file mode 100644 index 0000000..d40bb0ac --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/late-star-export-request.html
@@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>Late star-export request</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + window.log = []; + + const test_load = async_test( + "Test the situation where a module is instantiated without a use of " + + "its star-exports, but later on a different module requests them."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_array_equals(log, [ + "export-something", "export-something-nested", + "import-something-namespace", 42, 43]); + })); +</script> +<script type="module" src="export-something-nested.js"></script> +<script type="module"> + log.push("import-something-namespace"); + log.push(foo); + set_foo(43); + log.push(foo); + import {foo, set_foo} from "./export-something-nested.js"; +</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/missing-export-nested.js b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/missing-export-nested.js new file mode 100644 index 0000000..860d2bf --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/missing-export-nested.js
@@ -0,0 +1,2 @@ +import "./missing-export.js"; +log.push("nested-missing-export");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/missing-export.js b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/missing-export.js new file mode 100644 index 0000000..e6f5746e --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/missing-export.js
@@ -0,0 +1,2 @@ +import something from "./missing-export.js"; +log.push("missing-export");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/module-vs-script-1.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/module-vs-script-1.html new file mode 100644 index 0000000..ae82e13 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/module-vs-script-1.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<title>Once as module script, once as classic script</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + window.log = []; + + const test_load = async_test( + "Test that evaluating something as classic script does not prevent " + + "it from being evaluated as module script."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_array_equals(log, [window, undefined]); + })); +</script> +<script type="module" src="this.js"></script> +<script src="this.js"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/module-vs-script-2.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/module-vs-script-2.html new file mode 100644 index 0000000..2a879f3 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/module-vs-script-2.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<title>Once as classic script, once as module script</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + window.log = []; + + const test_load = async_test( + "Test that evaluating something as classic script does not prevent " + + "it from being evaluated as module script."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_array_equals(log, [window, undefined]); + })); +</script> +<script type="module" src="this.js"></script> +<script src="this.js"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/nested-missing-export.js b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/nested-missing-export.js new file mode 100644 index 0000000..3801ae8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/nested-missing-export.js
@@ -0,0 +1,2 @@ +import "./missing-export.js"; +log.push("missing-export-nested");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/nomodule-attribute.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/nomodule-attribute.html new file mode 100644 index 0000000..656c99b2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/nomodule-attribute.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<title>The 'nomodule' attribute</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + window.log = []; + + const test_load = async_test( + "Test that 'nomodule' has the desired effect on classic scripts, but " + + "no effect on module scripts."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_array_equals(log, [undefined]); + })); + +</script> +<script type="module" src="this.js" nomodule></script> +<script src="this.js" nomodule></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/single-evaluation-1.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/single-evaluation-1.html new file mode 100644 index 0000000..cc4e2d6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/single-evaluation-1.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<title>Single evaluation, 1</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + window.log = []; + + const test_load = async_test( + "Test that a module is evaluated only once, and that 'this' is " + + "undefined (because of strict mode)."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_array_equals(log, [undefined, "this-nested"]); + })); +</script> +<script type="module" src="this.js"></script> +<script type="module" src="this.js"></script> +<script type="module" src="this-nested.js"></script> +<script type="module" src="this.js"></script> +<script type="module" src="this-nested.js"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/single-evaluation-2.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/single-evaluation-2.html new file mode 100644 index 0000000..790e2fa --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/single-evaluation-2.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<title>Single evaluation, 2</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + window.log = []; + + const test_load = async_test( + "Test that a module is evaluated only once, and that 'this' is " + + "undefined (because of strict mode)."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_array_equals(log, [undefined, "this-nested"]); + })); +</script> +<script type="module" src="this-nested.js"></script> +<script type="module" src="this-nested.js"></script> +<script type="module" src="this.js"></script> +<script type="module" src="this-nested.js"></script> +<script type="module" src="this.js"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/specifier-error.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/specifier-error.html new file mode 100644 index 0000000..2cc393e --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/specifier-error.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<title>Handling of invalid specifiers</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + + const test_load = async_test( + "Test that invalid module specifier leads to TypeError on window."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_equals(log.length, 1); + assert_equals(log[0].constructor, TypeError); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./bad-module-specifier.js" onerror="unreachable()"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/syntaxerror-nested.js b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/syntaxerror-nested.js new file mode 100644 index 0000000..de1b053c --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/syntaxerror-nested.js
@@ -0,0 +1,2 @@ +import "./syntaxerror.js"; +log.push("nested-syntaxerror");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/syntaxerror.js b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/syntaxerror.js new file mode 100644 index 0000000..31a9e2c --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/syntaxerror.js
@@ -0,0 +1,2 @@ +log.push("syntaxerror"); +%!#$@#$@#$@
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/this-nested.js b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/this-nested.js new file mode 100644 index 0000000..f204812f --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/this-nested.js
@@ -0,0 +1,2 @@ +import "./this.js"; +log.push("this-nested");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/this.js b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/this.js new file mode 100644 index 0000000..996a439 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/this.js
@@ -0,0 +1 @@ +log.push(this);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/throw-nested.js b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/throw-nested.js new file mode 100644 index 0000000..f1801ea --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/throw-nested.js
@@ -0,0 +1,2 @@ +import "./throw.js"; +log.push("throw-nested");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/throw.js b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/throw.js new file mode 100644 index 0000000..cef79182 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/throw.js
@@ -0,0 +1,2 @@ +log.push("throw"); +throw {foo: true}
diff --git a/third_party/WebKit/LayoutTests/fast/block/hr-with-float.html b/third_party/WebKit/LayoutTests/fast/block/hr-with-float.html new file mode 100644 index 0000000..9f36470 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/block/hr-with-float.html
@@ -0,0 +1,24 @@ +<!DOCTYPE html> +<style> + .child { float:left; width:100%; height:100px; } +</style> +<p>There should be a blue square below.</p> +<div style="position:relative; width:100px;"> + <div style="float:left; width:50px; height:100px; background:blue;"></div> + <hr id="hr" style="width:50px; border:none; background:blue;"> +</div> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script> + // The HTML parser auto-terminates HR elements, so we need to add a child + // like this: + var child = document.createElement("div"); + child.className = "child"; + document.getElementById("hr").appendChild(child); + + test(() => { + var hr = document.getElementById("hr"); + assert_equals(hr.offsetLeft, 50); + assert_equals(hr.offsetHeight, 100); + }, "HR establishes a block formatting context"); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/ruby/float-overhang-from-ruby-text-expected.txt b/third_party/WebKit/LayoutTests/fast/ruby/float-overhang-from-ruby-text-expected.txt index c887524..4ffbd81 100644 --- a/third_party/WebKit/LayoutTests/fast/ruby/float-overhang-from-ruby-text-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/ruby/float-overhang-from-ruby-text-expected.txt
@@ -6,7 +6,7 @@ LayoutBlockFlow {DIV} at (0,0) size 784x75 LayoutRuby (inline) {RUBY} at (0,0) size 100x50 LayoutRubyRun (anonymous) at (0,25) size 100x50 - LayoutRubyText {RT} at (0,-25) size 100x25 + LayoutRubyText {RT} at (0,-25) size 100x50 LayoutText {#text} at (50,0) size 25x25 text run at (50,0) width 25: "a" LayoutBlockFlow (floating) {DIV} at (0,0) size 50x50 [bgcolor=#ADD8E6]
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/indexeddb/database-refresh-view-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/indexeddb/database-refresh-view-expected.txt new file mode 100644 index 0000000..f374ce0 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/indexeddb/database-refresh-view-expected.txt
@@ -0,0 +1,33 @@ +Tests refreshing the database information and data views. + +Dumping IndexedDB tree: + (empty) +Created database. +Dumping IndexedDB tree: + database: testDatabase - http://127.0.0.1:8000 + (no object stores) +Created first objectstore. +Dumping IndexedDB tree: + database: testDatabase - http://127.0.0.1:8000 + Object store: testObjectStore1 + Index: testIndex +Created second objectstore. +Dumping IndexedDB tree: + database: testDatabase - http://127.0.0.1:8000 + Object store: testObjectStore1 + Index: testIndex + Object store: testObjectStore2 + Index: testIndex +Added testObjectStore1 entry. +Dumping ObjectStore data: + Object store: testObjectStore1 + (no entries) + Object store: testObjectStore2 + (no entries) +Refreshed database. +Dumping ObjectStore data: + Object store: testObjectStore1 + Key = testKey, value = [object Object] + Object store: testObjectStore2 + (no entries) +
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/indexeddb/database-refresh-view.html b/third_party/WebKit/LayoutTests/http/tests/inspector/indexeddb/database-refresh-view.html new file mode 100644 index 0000000..d9c3bb0d --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/indexeddb/database-refresh-view.html
@@ -0,0 +1,187 @@ +<html> +<head> +<script src="../inspector-test.js"></script> +<script src="../resources-test.js"></script> +<script src="../console-test.js"></script> +<script src="indexeddb-test.js"></script> +<script> + +function onIndexedDBError(e) { + console.error("IndexedDB error: " + e); +} + +function createDatabase(databaseName) { + var callback; + var promise = new Promise((fulfill) => callback = fulfill); + var request = indexedDB.open(databaseName); + request.onerror = onIndexedDBError; + request.onsuccess = function(event) { + request.result.close(); + callback(); + } + return promise; +} + +function createObjectStore(databaseName, objectStoreName, indexName, keyPath) { + var callback; + var promise = new Promise((fulfill) => callback = fulfill); + var request = indexedDB.open(databaseName); + request.onerror = onIndexedDBError; + request.onsuccess = function(event) { + var db = request.result; + var version = db.version; + db.close(); + + var upgradeRequest = indexedDB.open(databaseName, version + 1); + + upgradeRequest.onerror = onIndexedDBError; + upgradeRequest.onupgradeneeded = function(e) { + var upgradeDb = e.target.result; + var store = upgradeDb.createObjectStore(objectStoreName, { keyPath: "test", autoIncrement: false }); + store.createIndex(indexName, "test", { unique: false, multiEntry: false }); + callback(); + } + upgradeRequest.onsuccess = function(e) { + var upgradeDb = e.target.result; + upgradeDb.close(); + callback(); + } + } + return promise; +} + +function addIDBValue(databaseName, objectStoreName, key, value) { + var callback; + var promise = new Promise((fulfill) => callback = fulfill); + var request = indexedDB.open(databaseName); + request.onerror = onIndexedDBError; + request.onsuccess = function(event) { + var db = request.result; + var transaction = db.transaction(objectStoreName, "readwrite"); + var store = transaction.objectStore(objectStoreName); + store.put({ test: key, testValue: value }); + + transaction.onerror = onIndexedDBError; + transaction.oncomplete = function() { + db.close(); + callback(); + }; + } + return promise; +} + +async function test() +{ + var databaseName = "testDatabase"; + var objectStoreName1 = "testObjectStore1"; + var objectStoreName2 = "testObjectStore2"; + var indexName = "testIndex"; + var keyPath = "testKey"; + + var indexedDBModel = InspectorTest.mainTarget.model(Resources.IndexedDBModel); + var databaseId; + + function waitRefreshDatabase(callback) { + var view = UI.panels.resources._sidebar.indexedDBListTreeElement._idbDatabaseTreeElements[0]._view; + InspectorTest.addSniffer(Resources.IDBDatabaseView.prototype, "_updatedForTests", callback, false); + view._refreshDatabaseButtonClicked(); + } + + function waitUpdateDataView(callback) { + InspectorTest.addSniffer(Resources.IDBDataView.prototype, "_updatedDataForTests", callback, false); + } + + function waitDatabaseLoaded(callback) { + var event = indexedDBModel.addEventListener(Resources.IndexedDBModel.Events.DatabaseLoaded, () => { + Common.EventTarget.removeEventListeners([event]); + callback(); + }); + } + + function waitDatabaseAdded(callback) { + var event = indexedDBModel.addEventListener(Resources.IndexedDBModel.Events.DatabaseAdded, () => { + Common.EventTarget.removeEventListeners([event]); + callback(); + }); + UI.panels.resources._sidebar.indexedDBListTreeElement.refreshIndexedDB(); + } + + function dumpObjectStores() { + InspectorTest.addResult("Dumping ObjectStore data:"); + + var idbDatabaseTreeElement = UI.panels.resources._sidebar.indexedDBListTreeElement._idbDatabaseTreeElements[0]; + for (var i = 0; i < idbDatabaseTreeElement.childCount(); ++i) { + var objectStoreTreeElement = idbDatabaseTreeElement.childAt(i); + InspectorTest.addResult(" Object store: " + objectStoreTreeElement.title); + var entries = objectStoreTreeElement._view._entries; + if (!entries.length) { + InspectorTest.addResult(" (no entries)"); + continue; + } + for (var j = 0; j < entries.length; ++j) { + InspectorTest.addResult(" Key = " + entries[j].key._value + ", value = " + entries[j].value); + } + } + } + + // Initial tree + InspectorTest.dumpIndexedDBTree(); + + // Create database + await InspectorTest.evaluateInPageAsync("createDatabase('" + databaseName + "')"); + await new Promise(waitDatabaseAdded); + var idbDatabaseTreeElement = UI.panels.resources._sidebar.indexedDBListTreeElement._idbDatabaseTreeElements[0]; + databaseId = idbDatabaseTreeElement._databaseId; + InspectorTest.addResult("Created database."); + InspectorTest.dumpIndexedDBTree(); + + // Load indexedDb database view + indexedDBModel.refreshDatabase(databaseId); // Initial database refresh. + await new Promise(waitDatabaseLoaded); // Needed to initialize database view, otherwise + idbDatabaseTreeElement.onselect(false); // IDBDatabaseTreeElement.database would be undefined. + var databaseView = idbDatabaseTreeElement._view; + + // Create first objectstore + await InspectorTest.evaluateInPageAsync("createObjectStore('" + databaseName + "', '" + objectStoreName1 + "', '" + indexName + "', '" + keyPath + "')"); + await new Promise(waitRefreshDatabase); + InspectorTest.addResult("Created first objectstore."); + InspectorTest.dumpIndexedDBTree(); + + // Create second objectstore + await InspectorTest.evaluateInPageAsync("createObjectStore('" + databaseName + "', '" + objectStoreName2 + "', '" + indexName + "', '" + keyPath + "')"); + await new Promise(waitRefreshDatabase); + InspectorTest.addResult("Created second objectstore."); + InspectorTest.dumpIndexedDBTree(); + + // Load objectstore data views + for (var i = 0; i < idbDatabaseTreeElement.childCount(); ++i) { + var objectStoreTreeElement = idbDatabaseTreeElement.childAt(i); + objectStoreTreeElement.onselect(false); + } + + // Add entries + await InspectorTest.evaluateInPageAsync("addIDBValue('" + databaseName + "', '" + objectStoreName1 + "', 'testKey', 'testValue')"); + InspectorTest.addResult("Added " + objectStoreName1 + " entry."); + dumpObjectStores(); + + // Refresh database view + await new Promise(waitRefreshDatabase); + for (var i = 0; i < idbDatabaseTreeElement.childCount(); ++i) { + var objectStoreTreeElement = idbDatabaseTreeElement.childAt(i); + if (objectStoreTreeElement._objectStore.name === objectStoreName1) { + objectStoreTreeElement.onselect(false); + break; + } + } + await new Promise(waitUpdateDataView); // Wait for objectstore data to load on page. + InspectorTest.addResult("Refreshed database."); + dumpObjectStores(); + + InspectorTest.completeTest(); +} +</script> +</head> +<body onload="runTest()"> +<p>Tests refreshing the database information and data views.</p> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/indexeddb/indexeddb-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/indexeddb/indexeddb-test.js index 9547f4a..cf36c59a 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/indexeddb/indexeddb-test.js +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/indexeddb/indexeddb-test.js
@@ -23,8 +23,8 @@ InspectorTest.addResult(" (no indexes)"); continue; } - for (var j = 0; j < objectStoreTreeElement.childCount(); ++j) { - var indexTreeElement = objectStoreTreeElement.childAt(j); + for (var k = 0; k < objectStoreTreeElement.childCount(); ++k) { + var indexTreeElement = objectStoreTreeElement.childAt(k); InspectorTest.addResult(" Index: " + indexTreeElement.title); } }
diff --git a/third_party/WebKit/LayoutTests/inspector/quick-open/command-menu-expected.txt b/third_party/WebKit/LayoutTests/inspector/quick-open/command-menu-expected.txt index 812da80..234966bf 100644 --- a/third_party/WebKit/LayoutTests/inspector/quick-open/command-menu-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector/quick-open/command-menu-expected.txt
@@ -10,6 +10,7 @@ Has category: Mobile Has category: Network Has category: Panel +Has category: Rendering Has category: Settings Has category: Sources
diff --git a/third_party/WebKit/LayoutTests/webaudio/tools/README.md b/third_party/WebKit/LayoutTests/webaudio/tools/README.md index 12ed3699..0c3baa6 100644 --- a/third_party/WebKit/LayoutTests/webaudio/tools/README.md +++ b/third_party/WebKit/LayoutTests/webaudio/tools/README.md
@@ -19,6 +19,8 @@ ## Installation +The `run-webkit-tests` script process all the files in the `webaudio/` directory, so files created by the node package installation will pollute the test result. To avoid this, copy `tools/` directory to another directory. Then run the following in that directory. + ``` cd ${WHERE_PACKAGE_JSON_IS} npm install ``` @@ -29,29 +31,22 @@ ## Usage ``` -node layout-test-tidy ${TARGET_PATH} +node layout-test-tidy [-[viR]] ${TARGET_PATH} ``` -When the target path is a directory, it scans all the files in the subdirectory. -Specifying a single file is also valid operation. +Available options: + * `-v` or `--verbose`: verbose output. Useful when collecting warnings and notes generated by the tool. + * `-i` or `--inplace`: in-place processing. Write directly into the original file. + * `-R` or `--recursive`: Expand the given path recursively. + +The result will be written to stdout, and only HTML and JS files with proper file extension (.html, .js) will be processed. + +### Examples ``` -node layout-test-tidy ${TARGET_PATH} -v > result.txt -``` +# To collect the result with warning/notes to a file. +node layout-test-tidy -v ${TARGET_PATH} > result.txt -By default, the result will be written to stdout, so you can pipe the result to -a file as shown above. `-v` or `--verbose` option is useful when collecting -warnings and notes generated by the tool. - +# Apply in-place tidy to the entire layout test files for WebAudio. +node layout-test-tidy -i -R ${CHROME_SRC}/third_party/WebKit/LayoutTests/webaudio ``` -node layout-test-tidy ${TARGET_PATH} -i -``` - -For in-place processing, use `-i` or `--inplace` switch. - -``` -node layout-test-tidy ${CHROME_SRC}/third_party/WebKit/LayoutTests/webaudio -``` - - - If there is a file to be skipped, simply create `skip-tidy` file and add - absolute file paths of files to be skipped.
diff --git a/third_party/WebKit/LayoutTests/webaudio/tools/layout-test-tidy.js b/third_party/WebKit/LayoutTests/webaudio/tools/layout-test-tidy.js index 4f3bbbd..f27a72b 100644 --- a/third_party/WebKit/LayoutTests/webaudio/tools/layout-test-tidy.js +++ b/third_party/WebKit/LayoutTests/webaudio/tools/layout-test-tidy.js
@@ -21,8 +21,13 @@ */ const OPTIONS = { - HTMLTidy: - {'indent': 'yes', 'indent-spaces': '2', 'wrap': '80', 'tidy-mark': 'no'}, + HTMLTidy: { + 'indent': 'yes', + 'indent-spaces': '2', + 'wrap': '80', + 'tidy-mark': 'no', + 'doctype': 'html5' + }, ClangFormat: ['-style=Chromium', '-assume-filename=a.js'], @@ -511,44 +516,33 @@ args = args.filter(arg => arg); - // A single target (a file or a directory) is allowed. - if (args.length !== 1) { - Util.logAndExit('main', 'Please specify a single target. (' + args + ')'); - } - // Populate options flags. let options = { - inPlace: optionArgs.includes('-i') || optionArgs.includes('--in-place'), - verbose: optionArgs.includes('-v') || optionArgs.includes('--verbose') + inplace: optionArgs.includes('-i') || optionArgs.includes('--inplace'), + recursive: optionArgs.includes('-R') || optionArgs.includes('--recursive'), + verbose: optionArgs.includes('-v') || optionArgs.includes('--verbose'), }; // Collect target file(s) from the file system. - let targetPath = args[0]; let files = []; - if (targetPath) { + args.forEach((targetPath) => { try { let stat = fs.lstatSync(targetPath); if (stat.isFile()) { - files.push(targetPath); - } else if (stat.isDirectory()) { - files = glob.sync( - targetPath + '/**/*.{html,js}', {ignore: ['**/node_modules/**/*']}); + let fileType = path.extname(targetPath); + if (fileType === '.html' || fileType === '.js') { + files.push(targetPath); + } + } else if ( + stat.isDirectory() && options.recursive && + !targetPath.includes('node_modules')) { + files = files.concat(glob.sync(targetPath + '/**/*.{html,js}')); } } catch (error) { let errorMessage = 'Invalid file path. (' + targetPath + ')\n' + ' > ' + error.toString(); Util.logAndExit('main', errorMessage); } - } - - // Files to be skipped. - let filesToBeSkipped = - Util.loadFileToStringSync('skip-tidy').toString().split('\n'); - filesToBeSkipped.forEach((fileSkipped) => { - let index = files.indexOf(fileSkipped); - if (index > -1) { - files.splice(index, 1); - } }); if (files.length > 0) {
diff --git a/third_party/WebKit/Source/core/css/html.css b/third_party/WebKit/Source/core/css/html.css index 57e64fe..854abfa4 100644 --- a/third_party/WebKit/Source/core/css/html.css +++ b/third_party/WebKit/Source/core/css/html.css
@@ -805,6 +805,8 @@ select:-internal-list-box hr { border-style: none; + -webkit-margin-before: 0.5em; + -webkit-margin-after: 0; } output {
diff --git a/third_party/WebKit/Source/core/editing/Editor.cpp b/third_party/WebKit/Source/core/editing/Editor.cpp index 1fb0a01f..ca84712 100644 --- a/third_party/WebKit/Source/core/editing/Editor.cpp +++ b/third_party/WebKit/Source/core/editing/Editor.cpp
@@ -1499,7 +1499,11 @@ // Ranges for selections that are no longer valid bool selection_did_not_change_dom_position = new_selection == GetFrame().Selection().GetSelectionInDOMTree(); - GetFrame().Selection().SetSelection(new_selection, options); + GetFrame().Selection().SetSelection( + SelectionInDOMTree::Builder(new_selection) + .SetIsHandleVisible(GetFrame().Selection().IsHandleVisible()) + .Build(), + options); // Some editing operations change the selection visually without affecting its // position within the DOM. For example when you press return in the following
diff --git a/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp b/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp index 7744dfb4..d2f1961 100644 --- a/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp +++ b/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp
@@ -71,7 +71,7 @@ const EphemeralRange& range = FirstEphemeralRangeOf(Selection().ComputeVisibleSelectionInDOMTree()); EXPECT_EQ(Position(sample->nextSibling(), 0), range.StartPosition()) - << "firstRagne() should return current selection value"; + << "firstRange() should return current selection value"; EXPECT_EQ(Position(sample->nextSibling(), 0), range.EndPosition()); } @@ -282,8 +282,8 @@ EXPECT_FALSE(Selection().IsHandleVisible()); Selection().SelectAll(); EXPECT_FALSE(Selection().IsHandleVisible()) - << "If handles weren't present before" - "selectAll. Then they shouldn't be present" + << "If handles weren't present before " + "selectAll. Then they shouldn't be present " "after it."; Selection().SetSelection(SelectionInDOMTree::Builder() @@ -293,11 +293,40 @@ EXPECT_TRUE(Selection().IsHandleVisible()); Selection().SelectAll(); EXPECT_TRUE(Selection().IsHandleVisible()) - << "If handles were present before" - "selectAll. Then they should be present" + << "If handles were present before " + "selectAll. Then they should be present " "after it."; } +TEST_F(FrameSelectionTest, BoldCommandPreservesHandle) { + SetBodyContent("<div id=sample>abc</div>"); + Element* sample = GetDocument().getElementById("sample"); + const Position end_of_text(sample->firstChild(), 3); + Selection().SetSelection(SelectionInDOMTree::Builder() + .Collapse(end_of_text) + .SetIsHandleVisible(false) + .Build()); + EXPECT_FALSE(Selection().IsHandleVisible()); + Selection().SelectAll(); + GetDocument().execCommand("bold", false, "", ASSERT_NO_EXCEPTION); + EXPECT_FALSE(Selection().IsHandleVisible()) + << "If handles weren't present before " + "bold command. Then they shouldn't " + "be present after it."; + + Selection().SetSelection(SelectionInDOMTree::Builder() + .Collapse(end_of_text) + .SetIsHandleVisible(true) + .Build()); + EXPECT_TRUE(Selection().IsHandleVisible()); + Selection().SelectAll(); + GetDocument().execCommand("bold", false, "", ASSERT_NO_EXCEPTION); + EXPECT_TRUE(Selection().IsHandleVisible()) + << "If handles were present before " + "bold command. Then they should " + "be present after it."; +} + TEST_F(FrameSelectionTest, SelectionOnRangeHidesHandles) { Text* text = AppendTextNode("Hello, World!"); GetDocument().View()->UpdateAllLifecyclePhases();
diff --git a/third_party/WebKit/Source/core/editing/SelectionController.cpp b/third_party/WebKit/Source/core/editing/SelectionController.cpp index ec1a74b..5c0399a 100644 --- a/third_party/WebKit/Source/core/editing/SelectionController.cpp +++ b/third_party/WebKit/Source/core/editing/SelectionController.cpp
@@ -215,10 +215,18 @@ // Shift+Click deselects when selection was created right-to-left const PositionInFlatTree& start = selection.Start(); const PositionInFlatTree& end = selection.end(); - const int distance_to_start = TextDistance(start, pos); - const int distance_to_end = TextDistance(pos, end); - builder.SetBaseAndExtent( - distance_to_start <= distance_to_end ? end : start, pos); + if (pos < start) { + // |distance_to_start < distance_to_end|. + builder.SetBaseAndExtent(end, pos); + } else if (end < pos) { + // |distance_to_start > distance_to_end|. + builder.SetBaseAndExtent(start, pos); + } else { + const int distance_to_start = TextDistance(start, pos); + const int distance_to_end = TextDistance(pos, end); + builder.SetBaseAndExtent( + distance_to_start <= distance_to_end ? end : start, pos); + } } UpdateSelectionForMouseDownDispatchingSelectStart(
diff --git a/third_party/WebKit/Source/core/editing/SelectionEditor.cpp b/third_party/WebKit/Source/core/editing/SelectionEditor.cpp index a5c9762..4f3e990c 100644 --- a/third_party/WebKit/Source/core/editing/SelectionEditor.cpp +++ b/third_party/WebKit/Source/core/editing/SelectionEditor.cpp
@@ -194,6 +194,7 @@ return; selection_ = SelectionInDOMTree::Builder() .SetBaseAndExtent(new_base, new_extent) + .SetIsHandleVisible(selection_.IsHandleVisible()) .Build(); MarkCacheDirty(); } @@ -211,6 +212,7 @@ return; selection_ = SelectionInDOMTree::Builder() .SetBaseAndExtent(new_base, new_extent) + .SetIsHandleVisible(selection_.IsHandleVisible()) .Build(); MarkCacheDirty(); }
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp index 2368499c4..91854ed 100644 --- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp +++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
@@ -182,6 +182,14 @@ } template <typename Strategy> +TextIteratorAlgorithm<Strategy>::TextIteratorAlgorithm( + const EphemeralRangeTemplate<Strategy>& range, + const TextIteratorBehavior& behavior) + : TextIteratorAlgorithm(range.StartPosition(), + range.EndPosition(), + behavior) {} + +template <typename Strategy> void TextIteratorAlgorithm<Strategy>::Initialize(Node* start_container, int start_offset, Node* end_container, @@ -254,18 +262,8 @@ } template <typename Strategy> -void TextIteratorAlgorithm<Strategy>::Advance() { - if (should_stop_) - return; - - if (node_) - DCHECK(!node_->GetDocument().NeedsLayoutTreeUpdate()) << node_; - - text_state_.ResetRunInformation(); - - // TODO(xiaochengh): Wrap the following code into HandleRememberedProgress(). - - // handle remembered node that needed a newline after the text node's newline +bool TextIteratorAlgorithm<Strategy>::HandleRememberedProgress() { + // Handle remembered node that needed a newline after the text node's newline if (needs_another_newline_) { // Emit the extra newline, and position it *inside* m_node, after m_node's // contents, in case it's a block, in the same way that we position the @@ -277,10 +275,30 @@ Node* base_node = last_child ? last_child : node_.Get(); SpliceBuffer('\n', Strategy::Parent(*base_node), base_node, 1, 1); needs_another_newline_ = false; - return; + return true; } - if (text_node_handler_.HandleRemainingTextRuns()) + // TODO(xiaochengh): When multiple text runs should be emitted from a replaced + // element or non-text node, we should handle it directly from here, instead + // of going into the main iteration of Advance() for multiple times. In this + // way, we can also remove the return values of HandleReplaceElement() and + // HandleNonTextNode(), and make the control flow cleaner. + + // Try to emit more text runs if we are handling a text node. + return text_node_handler_.HandleRemainingTextRuns(); +} + +template <typename Strategy> +void TextIteratorAlgorithm<Strategy>::Advance() { + if (should_stop_) + return; + + if (node_) + DCHECK(!node_->GetDocument().NeedsLayoutTreeUpdate()) << node_; + + text_state_.ResetRunInformation(); + + if (HandleRememberedProgress()) return; while (node_ && (node_ != past_end_node_ || shadow_depth_ > 0)) {
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.h b/third_party/WebKit/Source/core/editing/iterators/TextIterator.h index fd420e0..9e72c11c 100644 --- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.h +++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.h
@@ -59,6 +59,12 @@ TextIteratorAlgorithm(const PositionTemplate<Strategy>& start, const PositionTemplate<Strategy>& end, const TextIteratorBehavior& = TextIteratorBehavior()); + + // Same behavior as previous constructor but takes an EphemeralRange instead + // of two Positions + TextIteratorAlgorithm(const EphemeralRangeTemplate<Strategy>&, + const TextIteratorBehavior& = TextIteratorBehavior()); + ~TextIteratorAlgorithm(); bool AtEnd() const { return !text_state_.PositionNode() || should_stop_; } @@ -131,6 +137,9 @@ bool ShouldEmitSpaceBeforeAndAfterNode(Node*); void RepresentNodeOffsetZero(); + // Returns true if text is emitted from the remembered progress (if any). + bool HandleRememberedProgress(); + // Return true if the iteration progress should advance to |kHandledNode| // after calling a |HandleXXX| function. // TODO(xiaochengh): The meaning of the return values is unclear, and they do
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarker.h b/third_party/WebKit/Source/core/editing/markers/DocumentMarker.h index 0171ea10..6d76290 100644 --- a/third_party/WebKit/Source/core/editing/markers/DocumentMarker.h +++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarker.h
@@ -136,7 +136,6 @@ unsigned start_offset, unsigned end_offset, const String& description); - DocumentMarker(unsigned start_offset, unsigned end_offset, MatchStatus); DocumentMarker(unsigned start_offset, unsigned end_offset, Color underline_color, @@ -176,6 +175,9 @@ DECLARE_TRACE(); + protected: + DocumentMarker(unsigned start_offset, unsigned end_offset, MatchStatus); + private: MarkerType type_; unsigned start_offset_;
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp index c0e1f718..83cfe300 100644 --- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp +++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
@@ -159,9 +159,9 @@ for (TextIterator marked_text(range.StartPosition(), range.EndPosition()); !marked_text.AtEnd(); marked_text.Advance()) { AddMarker(marked_text.CurrentContainer(), - new DocumentMarker(marked_text.StartOffsetInCurrentContainer(), - marked_text.EndOffsetInCurrentContainer(), - match_status)); + new TextMatchMarker(marked_text.StartOffsetInCurrentContainer(), + marked_text.EndOffsetInCurrentContainer(), + match_status)); } // Don't invalidate tickmarks here. TextFinder invalidates tickmarks using a // throttling algorithm. crbug.com/6819.
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditorTest.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditorTest.cpp index 87a5818..a1976a15 100644 --- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditorTest.cpp +++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditorTest.cpp
@@ -4,6 +4,7 @@ #include "core/editing/markers/DocumentMarkerListEditor.h" +#include "core/editing/markers/TextMatchMarker.h" #include "testing/gtest/include/gtest/gtest.h" namespace blink { @@ -11,8 +12,8 @@ class DocumentMarkerListEditorTest : public ::testing::Test { protected: DocumentMarker* CreateMarker(unsigned startOffset, unsigned endOffset) { - return new DocumentMarker(startOffset, endOffset, - DocumentMarker::MatchStatus::kInactive); + return new TextMatchMarker(startOffset, endOffset, + DocumentMarker::MatchStatus::kInactive); } };
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerTest.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerTest.cpp index aa9d87f..1291ad2 100644 --- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerTest.cpp +++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerTest.cpp
@@ -4,6 +4,7 @@ #include "core/editing/markers/DocumentMarker.h" +#include "core/editing/markers/TextMatchMarker.h" #include "testing/gtest/include/gtest/gtest.h" namespace blink { @@ -13,8 +14,8 @@ class DocumentMarkerTest : public ::testing::Test { protected: DocumentMarker* CreateMarker(unsigned startOffset, unsigned endOffset) { - return new DocumentMarker(startOffset, endOffset, - DocumentMarker::MatchStatus::kInactive); + return new TextMatchMarker(startOffset, endOffset, + DocumentMarker::MatchStatus::kInactive); } };
diff --git a/third_party/WebKit/Source/core/editing/markers/TextMatchMarker.h b/third_party/WebKit/Source/core/editing/markers/TextMatchMarker.h index 74c69dd4..c6c87b1 100644 --- a/third_party/WebKit/Source/core/editing/markers/TextMatchMarker.h +++ b/third_party/WebKit/Source/core/editing/markers/TextMatchMarker.h
@@ -37,9 +37,11 @@ enum class State { kInvalid, kValidNull, kValidNotNull }; public: - static TextMatchMarker* Create(const DocumentMarker& marker) { - return new TextMatchMarker(marker); - } + TextMatchMarker(unsigned start_offset, + unsigned end_offset, + MatchStatus status) + : DocumentMarker(start_offset, end_offset, status), + state_(State::kInvalid) {} bool IsRendered() const { return state_ == State::kValidNotNull; } bool Contains(const LayoutPoint& point) const {
diff --git a/third_party/WebKit/Source/core/editing/markers/TextMatchMarkerListImpl.cpp b/third_party/WebKit/Source/core/editing/markers/TextMatchMarkerListImpl.cpp index 7cd3231f..18a5d75a 100644 --- a/third_party/WebKit/Source/core/editing/markers/TextMatchMarkerListImpl.cpp +++ b/third_party/WebKit/Source/core/editing/markers/TextMatchMarkerListImpl.cpp
@@ -22,8 +22,8 @@ } void TextMatchMarkerListImpl::Add(DocumentMarker* marker) { - DocumentMarkerListEditor::AddMarkerWithoutMergingOverlapping( - &markers_, TextMatchMarker::Create(*marker)); + DocumentMarkerListEditor::AddMarkerWithoutMergingOverlapping(&markers_, + marker); } void TextMatchMarkerListImpl::Clear() {
diff --git a/third_party/WebKit/Source/core/editing/markers/TextMatchMarkerListImplTest.cpp b/third_party/WebKit/Source/core/editing/markers/TextMatchMarkerListImplTest.cpp index 2731906a..ad26bac 100644 --- a/third_party/WebKit/Source/core/editing/markers/TextMatchMarkerListImplTest.cpp +++ b/third_party/WebKit/Source/core/editing/markers/TextMatchMarkerListImplTest.cpp
@@ -5,6 +5,7 @@ #include "core/editing/markers/TextMatchMarkerListImpl.h" #include "core/editing/EditingTestBase.h" +#include "core/editing/markers/TextMatchMarker.h" namespace blink { @@ -13,8 +14,8 @@ TextMatchMarkerListImplTest() : marker_list_(new TextMatchMarkerListImpl()) {} DocumentMarker* CreateMarker(unsigned start_offset, unsigned end_offset) { - return new DocumentMarker(start_offset, end_offset, - DocumentMarker::MatchStatus::kInactive); + return new TextMatchMarker(start_offset, end_offset, + DocumentMarker::MatchStatus::kInactive); } Persistent<TextMatchMarkerListImpl> marker_list_;
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp index 051fd2e..a72600ab 100644 --- a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp +++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
@@ -600,7 +600,6 @@ // and should be rewritten. // Expand the range to encompass entire paragraphs, since text checking needs // that much context. - int selection_offset = 0; int ambiguous_boundary_offset = -1; if (GetFrame().Selection().ComputeVisibleSelectionInDOMTree().IsCaret()) { @@ -609,7 +608,11 @@ // Attempt to save the caret position so we can restore it later if needed const Position& caret_position = GetFrame().Selection().ComputeVisibleSelectionInDOMTree().end(); - selection_offset = paragraph.OffsetTo(caret_position); + const Position& paragraph_start = checking_range.StartPosition(); + const int selection_offset = + paragraph_start < caret_position + ? TextIterator::RangeLength(paragraph_start, caret_position) + : 0; if (selection_offset > 0 && static_cast<unsigned>(selection_offset) <= paragraph.GetText().length() &&
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingParagraph.cpp b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingParagraph.cpp index 6f8f18d..b9aeb06c 100644 --- a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingParagraph.cpp +++ b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingParagraph.cpp
@@ -99,11 +99,6 @@ character_count); } -int TextCheckingParagraph::OffsetTo(const Position& position) const { - DCHECK(checking_range_.IsNotNull()); - return TextIterator::RangeLength(OffsetAsRange().StartPosition(), position); -} - bool TextCheckingParagraph::IsEmpty() const { // Both predicates should have same result, but we check both just to be sure. // We need to investigate to remove this redundancy.
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingParagraph.h b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingParagraph.h index 24d9cae0..dc0670e 100644 --- a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingParagraph.h +++ b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingParagraph.h
@@ -41,7 +41,6 @@ int RangeLength() const; EphemeralRange Subrange(int character_offset, int character_count) const; - int OffsetTo(const Position&) const; void ExpandRangeToNextEnd(); const String& GetText() const;
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.cpp b/third_party/WebKit/Source/core/frame/LocalFrame.cpp index 3eefa4f..7cafbe02 100644 --- a/third_party/WebKit/Source/core/frame/LocalFrame.cpp +++ b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
@@ -1201,4 +1201,13 @@ return nullptr; } +void LocalFrame::SetViewportIntersectionFromParent( + const IntRect& viewport_intersection) { + if (remote_viewport_intersection_ != viewport_intersection) { + remote_viewport_intersection_ = viewport_intersection; + if (View()) + View()->ScheduleAnimation(); + } +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.h b/third_party/WebKit/Source/core/frame/LocalFrame.h index d29aea93..f49e7d09 100644 --- a/third_party/WebKit/Source/core/frame/LocalFrame.h +++ b/third_party/WebKit/Source/core/frame/LocalFrame.h
@@ -255,6 +255,12 @@ // focused element or passed node into explicit methods. WebPluginContainerBase* GetWebPluginContainerBase(Node* = nullptr) const; + // Called on a view for a LocalFrame with a RemoteFrame parent. This makes + // viewport intersection available that accounts for remote ancestor frames + // and their respective scroll positions, clips, etc. + void SetViewportIntersectionFromParent(const IntRect&); + IntRect RemoteViewportIntersection() { return remote_viewport_intersection_; } + private: friend class FrameNavigationDisabler; @@ -305,6 +311,8 @@ InterfaceProvider* const interface_provider_; InterfaceRegistry* const interface_registry_; + + IntRect remote_viewport_intersection_; }; inline FrameLoader& LocalFrame::Loader() const {
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp index eb769944..aaa69d2 100644 --- a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp +++ b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
@@ -1060,32 +1060,38 @@ // functions so that a single human could understand what layout() is actually // doing. + // FIXME: ForceLayoutParentViewIfNeeded can cause this document's lifecycle + // to change, which should not happen. ForceLayoutParentViewIfNeeded(); - // TODO(szager): Remove this after checking crash reports. - CHECK(IsInPerformLayout()); + CHECK(IsInPerformLayout() || + Lifecycle().GetState() >= DocumentLifecycle::kLayoutClean); - if (in_subtree_layout) { - if (analyzer_) { - analyzer_->Increment(LayoutAnalyzer::kPerformLayoutRootLayoutObjects, - layout_subtree_root_list_.size()); - } - for (auto& root : layout_subtree_root_list_.Ordered()) { - if (!root->NeedsLayout()) - continue; - LayoutFromRootObject(*root); + if (IsInPerformLayout()) { + if (in_subtree_layout) { + if (analyzer_) { + analyzer_->Increment(LayoutAnalyzer::kPerformLayoutRootLayoutObjects, + layout_subtree_root_list_.size()); + } + for (auto& root : layout_subtree_root_list_.Ordered()) { + if (!root->NeedsLayout()) + continue; + LayoutFromRootObject(*root); - // We need to ensure that we mark up all layoutObjects up to the - // LayoutView for paint invalidation. This simplifies our code as we just - // always do a full tree walk. - if (LayoutItem container = LayoutItem(root->Container())) - container.SetMayNeedPaintInvalidation(); + // We need to ensure that we mark up all layoutObjects up to the + // LayoutView for paint invalidation. This simplifies our code as we + // just always do a full tree walk. + if (LayoutItem container = LayoutItem(root->Container())) + container.SetMayNeedPaintInvalidation(); + } + layout_subtree_root_list_.Clear(); + } else { + if (HasOrthogonalWritingModeRoots() && + !RuntimeEnabledFeatures::layoutNGEnabled()) + LayoutOrthogonalWritingModeRoots(); + GetLayoutView()->UpdateLayout(); } - layout_subtree_root_list_.Clear(); } else { - if (HasOrthogonalWritingModeRoots() && - !RuntimeEnabledFeatures::layoutNGEnabled()) - LayoutOrthogonalWritingModeRoots(); - GetLayoutView()->UpdateLayout(); + DCHECK(!NeedsLayout()); } frame_->GetDocument()->Fetcher()->UpdateAllImageResourcePriorities(); @@ -5319,16 +5325,8 @@ return result; } -void LocalFrameView::SetViewportIntersectionFromParent( - const IntRect& viewport_intersection) { - if (remote_viewport_intersection_ != viewport_intersection) { - remote_viewport_intersection_ = viewport_intersection; - ScheduleAnimation(); - } -} - IntRect LocalFrameView::RemoteViewportIntersection() { - IntRect intersection(remote_viewport_intersection_); + IntRect intersection(GetFrame().RemoteViewportIntersection()); intersection.Move(ScrollOffsetInt()); return intersection; }
diff --git a/third_party/WebKit/Source/core/inspector/BUILD.gn b/third_party/WebKit/Source/core/inspector/BUILD.gn index 66150a0..1d9705b 100644 --- a/third_party/WebKit/Source/core/inspector/BUILD.gn +++ b/third_party/WebKit/Source/core/inspector/BUILD.gn
@@ -20,6 +20,8 @@ "DOMEditor.h", "DOMPatchSupport.cpp", "DOMPatchSupport.h", + "DevToolsEmulator.cpp", + "DevToolsEmulator.h", "DevToolsHost.cpp", "DevToolsHost.h", "IdentifiersFactory.cpp",
diff --git a/third_party/WebKit/Source/web/DevToolsEmulator.cpp b/third_party/WebKit/Source/core/inspector/DevToolsEmulator.cpp similarity index 72% rename from third_party/WebKit/Source/web/DevToolsEmulator.cpp rename to third_party/WebKit/Source/core/inspector/DevToolsEmulator.cpp index c3688af..95ef80d 100644 --- a/third_party/WebKit/Source/web/DevToolsEmulator.cpp +++ b/third_party/WebKit/Source/core/inspector/DevToolsEmulator.cpp
@@ -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 "web/DevToolsEmulator.h" +#include "core/inspector/DevToolsEmulator.h" #include "core/events/WebInputEventConversion.h" #include "core/exported/WebViewBase.h" @@ -22,7 +22,7 @@ #include "platform/loader/fetch/MemoryCache.h" #include "platform/wtf/PtrUtil.h" #include "public/platform/WebLayerTreeView.h" -#include "web/WebSettingsImpl.h" +#include "public/web/WebSettings.h" namespace { @@ -59,8 +59,8 @@ namespace blink { -DevToolsEmulator::DevToolsEmulator(WebViewBase* web_view_impl) - : web_view_impl_(web_view_impl), +DevToolsEmulator::DevToolsEmulator(WebViewBase* web_view) + : web_view_(web_view), device_metrics_enabled_(false), emulate_mobile_enabled_(false), is_overlay_scrollbars_enabled_(false), @@ -69,27 +69,27 @@ original_default_minimum_page_scale_factor_(0), original_default_maximum_page_scale_factor_(0), embedder_text_autosizing_enabled_( - web_view_impl->GetPage()->GetSettings().TextAutosizingEnabled()), + web_view->GetPage()->GetSettings().TextAutosizingEnabled()), embedder_device_scale_adjustment_( - web_view_impl->GetPage()->GetSettings().GetDeviceScaleAdjustment()), + web_view->GetPage()->GetSettings().GetDeviceScaleAdjustment()), embedder_prefer_compositing_to_lcd_text_enabled_( - web_view_impl->GetPage() + web_view->GetPage() ->GetSettings() .GetPreferCompositingToLCDTextEnabled()), embedder_viewport_style_( - web_view_impl->GetPage()->GetSettings().GetViewportStyle()), + web_view->GetPage()->GetSettings().GetViewportStyle()), embedder_plugins_enabled_( - web_view_impl->GetPage()->GetSettings().GetPluginsEnabled()), + web_view->GetPage()->GetSettings().GetPluginsEnabled()), embedder_available_pointer_types_( - web_view_impl->GetPage()->GetSettings().GetAvailablePointerTypes()), + web_view->GetPage()->GetSettings().GetAvailablePointerTypes()), embedder_primary_pointer_type_( - web_view_impl->GetPage()->GetSettings().GetPrimaryPointerType()), + web_view->GetPage()->GetSettings().GetPrimaryPointerType()), embedder_available_hover_types_( - web_view_impl->GetPage()->GetSettings().GetAvailableHoverTypes()), + web_view->GetPage()->GetSettings().GetAvailableHoverTypes()), embedder_primary_hover_type_( - web_view_impl->GetPage()->GetSettings().GetPrimaryHoverType()), + web_view->GetPage()->GetSettings().GetPrimaryHoverType()), embedder_main_frame_resizes_are_orientation_changes_( - web_view_impl->GetPage() + web_view->GetPage() ->GetSettings() .GetMainFrameResizesAreOrientationChanges()), touch_event_emulation_enabled_(false), @@ -98,7 +98,7 @@ original_device_supports_touch_(false), original_max_touch_points_(0), embedder_script_enabled_( - web_view_impl->GetPage()->GetSettings().GetScriptEnabled()), + web_view->GetPage()->GetSettings().GetScriptEnabled()), script_execution_disabled_(false) {} DevToolsEmulator::~DevToolsEmulator() {} @@ -114,26 +114,27 @@ bool emulate_mobile_enabled = device_metrics_enabled_ && emulate_mobile_enabled_; if (!emulate_mobile_enabled) - web_view_impl_->GetPage()->GetSettings().SetTextAutosizingEnabled(enabled); + web_view_->GetPage()->GetSettings().SetTextAutosizingEnabled(enabled); } void DevToolsEmulator::SetDeviceScaleAdjustment(float device_scale_adjustment) { embedder_device_scale_adjustment_ = device_scale_adjustment; bool emulate_mobile_enabled = device_metrics_enabled_ && emulate_mobile_enabled_; - if (!emulate_mobile_enabled) - web_view_impl_->GetPage()->GetSettings().SetDeviceScaleAdjustment( + if (!emulate_mobile_enabled) { + web_view_->GetPage()->GetSettings().SetDeviceScaleAdjustment( device_scale_adjustment); + } } void DevToolsEmulator::SetPreferCompositingToLCDTextEnabled(bool enabled) { embedder_prefer_compositing_to_lcd_text_enabled_ = enabled; bool emulate_mobile_enabled = device_metrics_enabled_ && emulate_mobile_enabled_; - if (!emulate_mobile_enabled) - web_view_impl_->GetPage() - ->GetSettings() - .SetPreferCompositingToLCDTextEnabled(enabled); + if (!emulate_mobile_enabled) { + web_view_->GetPage()->GetSettings().SetPreferCompositingToLCDTextEnabled( + enabled); + } } void DevToolsEmulator::SetViewportStyle(WebViewportStyle style) { @@ -141,7 +142,7 @@ bool emulate_mobile_enabled = device_metrics_enabled_ && emulate_mobile_enabled_; if (!emulate_mobile_enabled) - web_view_impl_->GetPage()->GetSettings().SetViewportStyle(style); + web_view_->GetPage()->GetSettings().SetViewportStyle(style); } void DevToolsEmulator::SetPluginsEnabled(bool enabled) { @@ -149,13 +150,13 @@ bool emulate_mobile_enabled = device_metrics_enabled_ && emulate_mobile_enabled_; if (!emulate_mobile_enabled) - web_view_impl_->GetPage()->GetSettings().SetPluginsEnabled(enabled); + web_view_->GetPage()->GetSettings().SetPluginsEnabled(enabled); } void DevToolsEmulator::SetScriptEnabled(bool enabled) { embedder_script_enabled_ = enabled; if (!script_execution_disabled_) - web_view_impl_->GetPage()->GetSettings().SetScriptEnabled(enabled); + web_view_->GetPage()->GetSettings().SetScriptEnabled(enabled); } void DevToolsEmulator::SetDoubleTapToZoomEnabled(bool enabled) { @@ -170,10 +171,11 @@ embedder_main_frame_resizes_are_orientation_changes_ = value; bool emulate_mobile_enabled = device_metrics_enabled_ && emulate_mobile_enabled_; - if (!emulate_mobile_enabled) - web_view_impl_->GetPage() + if (!emulate_mobile_enabled) { + web_view_->GetPage() ->GetSettings() .SetMainFrameResizesAreOrientationChanges(value); + } } void DevToolsEmulator::SetAvailablePointerTypes(int types) { @@ -181,7 +183,7 @@ bool emulate_mobile_enabled = device_metrics_enabled_ && emulate_mobile_enabled_; if (!emulate_mobile_enabled) - web_view_impl_->GetPage()->GetSettings().SetAvailablePointerTypes(types); + web_view_->GetPage()->GetSettings().SetAvailablePointerTypes(types); } void DevToolsEmulator::SetPrimaryPointerType(PointerType pointer_type) { @@ -189,8 +191,7 @@ bool emulate_mobile_enabled = device_metrics_enabled_ && emulate_mobile_enabled_; if (!emulate_mobile_enabled) - web_view_impl_->GetPage()->GetSettings().SetPrimaryPointerType( - pointer_type); + web_view_->GetPage()->GetSettings().SetPrimaryPointerType(pointer_type); } void DevToolsEmulator::SetAvailableHoverTypes(int types) { @@ -198,7 +199,7 @@ bool emulate_mobile_enabled = device_metrics_enabled_ && emulate_mobile_enabled_; if (!emulate_mobile_enabled) - web_view_impl_->GetPage()->GetSettings().SetAvailableHoverTypes(types); + web_view_->GetPage()->GetSettings().SetAvailableHoverTypes(types); } void DevToolsEmulator::SetPrimaryHoverType(HoverType hover_type) { @@ -206,7 +207,7 @@ bool emulate_mobile_enabled = device_metrics_enabled_ && emulate_mobile_enabled_; if (!emulate_mobile_enabled) - web_view_impl_->GetPage()->GetSettings().SetPrimaryHoverType(hover_type); + web_view_->GetPage()->GetSettings().SetPrimaryHoverType(hover_type); } void DevToolsEmulator::EnableDeviceEmulation( @@ -226,7 +227,7 @@ emulation_params_ = params; device_metrics_enabled_ = true; - web_view_impl_->GetPage()->GetSettings().SetDeviceScaleAdjustment( + web_view_->GetPage()->GetSettings().SetDeviceScaleAdjustment( calculateDeviceScaleAdjustment(params.view_size.width, params.view_size.height, params.device_scale_factor)); @@ -236,14 +237,13 @@ else DisableMobileEmulation(); - web_view_impl_->SetCompositorDeviceScaleFactorOverride( - params.device_scale_factor); + web_view_->SetCompositorDeviceScaleFactorOverride(params.device_scale_factor); UpdateRootLayerTransform(); // TODO(dgozman): mainFrameImpl() is null when it's remote. Figure out how // we end up with enabling emulation in this case. - if (web_view_impl_->MainFrameImpl()) { + if (web_view_->MainFrameImpl()) { if (Document* document = - web_view_impl_->MainFrameImpl()->GetFrame()->GetDocument()) + web_view_->MainFrameImpl()->GetFrame()->GetDocument()) document->MediaQueryAffectingValueChanged(); } } @@ -254,16 +254,16 @@ GetMemoryCache()->EvictResources(); device_metrics_enabled_ = false; - web_view_impl_->GetPage()->GetSettings().SetDeviceScaleAdjustment( + web_view_->GetPage()->GetSettings().SetDeviceScaleAdjustment( embedder_device_scale_adjustment_); DisableMobileEmulation(); - web_view_impl_->SetCompositorDeviceScaleFactorOverride(0.f); - web_view_impl_->SetPageScaleFactor(1.f); + web_view_->SetCompositorDeviceScaleFactorOverride(0.f); + web_view_->SetPageScaleFactor(1.f); UpdateRootLayerTransform(); // mainFrameImpl() could be null during cleanup or remote <-> local swap. - if (web_view_impl_->MainFrameImpl()) { + if (web_view_->MainFrameImpl()) { if (Document* document = - web_view_impl_->MainFrameImpl()->GetFrame()->GetDocument()) + web_view_->MainFrameImpl()->GetFrame()->GetDocument()) document->MediaQueryAffectingValueChanged(); } } @@ -282,37 +282,34 @@ RuntimeEnabledFeatures::mobileLayoutThemeEnabled(); RuntimeEnabledFeatures::setMobileLayoutThemeEnabled(true); ComputedStyle::InvalidateInitialStyle(); - web_view_impl_->GetPage()->GetSettings().SetViewportStyle( + web_view_->GetPage()->GetSettings().SetViewportStyle( WebViewportStyle::kMobile); - web_view_impl_->GetPage()->GetSettings().SetViewportEnabled(true); - web_view_impl_->GetPage()->GetSettings().SetViewportMetaEnabled(true); - web_view_impl_->GetPage()->GetVisualViewport().InitializeScrollbars(); - web_view_impl_->GetSettings()->SetShrinksViewportContentToFit(true); - web_view_impl_->GetPage()->GetSettings().SetTextAutosizingEnabled(true); - web_view_impl_->GetPage()->GetSettings().SetPreferCompositingToLCDTextEnabled( + web_view_->GetPage()->GetSettings().SetViewportEnabled(true); + web_view_->GetPage()->GetSettings().SetViewportMetaEnabled(true); + web_view_->GetPage()->GetVisualViewport().InitializeScrollbars(); + web_view_->GetSettings()->SetShrinksViewportContentToFit(true); + web_view_->GetPage()->GetSettings().SetTextAutosizingEnabled(true); + web_view_->GetPage()->GetSettings().SetPreferCompositingToLCDTextEnabled( true); - web_view_impl_->GetPage()->GetSettings().SetPluginsEnabled(false); - web_view_impl_->GetPage()->GetSettings().SetAvailablePointerTypes( + web_view_->GetPage()->GetSettings().SetPluginsEnabled(false); + web_view_->GetPage()->GetSettings().SetAvailablePointerTypes( kPointerTypeCoarse); - web_view_impl_->GetPage()->GetSettings().SetPrimaryPointerType( - kPointerTypeCoarse); - web_view_impl_->GetPage()->GetSettings().SetAvailableHoverTypes( - kHoverTypeNone); - web_view_impl_->GetPage()->GetSettings().SetPrimaryHoverType(kHoverTypeNone); - web_view_impl_->GetPage() - ->GetSettings() - .SetMainFrameResizesAreOrientationChanges(true); - web_view_impl_->SetZoomFactorOverride(1); + web_view_->GetPage()->GetSettings().SetPrimaryPointerType(kPointerTypeCoarse); + web_view_->GetPage()->GetSettings().SetAvailableHoverTypes(kHoverTypeNone); + web_view_->GetPage()->GetSettings().SetPrimaryHoverType(kHoverTypeNone); + web_view_->GetPage()->GetSettings().SetMainFrameResizesAreOrientationChanges( + true); + web_view_->SetZoomFactorOverride(1); original_default_minimum_page_scale_factor_ = - web_view_impl_->DefaultMinimumPageScaleFactor(); + web_view_->DefaultMinimumPageScaleFactor(); original_default_maximum_page_scale_factor_ = - web_view_impl_->DefaultMaximumPageScaleFactor(); - web_view_impl_->SetDefaultPageScaleLimits(0.25f, 5); + web_view_->DefaultMaximumPageScaleFactor(); + web_view_->SetDefaultPageScaleLimits(0.25f, 5); // TODO(dgozman): mainFrameImpl() is null when it's remote. Figure out how // we end up with enabling emulation in this case. - if (web_view_impl_->MainFrameImpl()) - web_view_impl_->MainFrameImpl()->GetFrameView()->UpdateLayout(); + if (web_view_->MainFrameImpl()) + web_view_->MainFrameImpl()->GetFrameView()->UpdateLayout(); } void DevToolsEmulator::DisableMobileEmulation() { @@ -325,50 +322,48 @@ RuntimeEnabledFeatures::setMobileLayoutThemeEnabled( is_mobile_layout_theme_enabled_); ComputedStyle::InvalidateInitialStyle(); - web_view_impl_->GetPage()->GetSettings().SetViewportEnabled(false); - web_view_impl_->GetPage()->GetSettings().SetViewportMetaEnabled(false); - web_view_impl_->GetPage()->GetVisualViewport().InitializeScrollbars(); - web_view_impl_->GetSettings()->SetShrinksViewportContentToFit(false); - web_view_impl_->GetPage()->GetSettings().SetTextAutosizingEnabled( + web_view_->GetPage()->GetSettings().SetViewportEnabled(false); + web_view_->GetPage()->GetSettings().SetViewportMetaEnabled(false); + web_view_->GetPage()->GetVisualViewport().InitializeScrollbars(); + web_view_->GetSettings()->SetShrinksViewportContentToFit(false); + web_view_->GetPage()->GetSettings().SetTextAutosizingEnabled( embedder_text_autosizing_enabled_); - web_view_impl_->GetPage()->GetSettings().SetPreferCompositingToLCDTextEnabled( + web_view_->GetPage()->GetSettings().SetPreferCompositingToLCDTextEnabled( embedder_prefer_compositing_to_lcd_text_enabled_); - web_view_impl_->GetPage()->GetSettings().SetViewportStyle( + web_view_->GetPage()->GetSettings().SetViewportStyle( embedder_viewport_style_); - web_view_impl_->GetPage()->GetSettings().SetPluginsEnabled( + web_view_->GetPage()->GetSettings().SetPluginsEnabled( embedder_plugins_enabled_); - web_view_impl_->GetPage()->GetSettings().SetAvailablePointerTypes( + web_view_->GetPage()->GetSettings().SetAvailablePointerTypes( embedder_available_pointer_types_); - web_view_impl_->GetPage()->GetSettings().SetPrimaryPointerType( + web_view_->GetPage()->GetSettings().SetPrimaryPointerType( embedder_primary_pointer_type_); - web_view_impl_->GetPage()->GetSettings().SetAvailableHoverTypes( + web_view_->GetPage()->GetSettings().SetAvailableHoverTypes( embedder_available_hover_types_); - web_view_impl_->GetPage()->GetSettings().SetPrimaryHoverType( + web_view_->GetPage()->GetSettings().SetPrimaryHoverType( embedder_primary_hover_type_); - web_view_impl_->GetPage() - ->GetSettings() - .SetMainFrameResizesAreOrientationChanges( - embedder_main_frame_resizes_are_orientation_changes_); - web_view_impl_->SetZoomFactorOverride(0); + web_view_->GetPage()->GetSettings().SetMainFrameResizesAreOrientationChanges( + embedder_main_frame_resizes_are_orientation_changes_); + web_view_->SetZoomFactorOverride(0); emulate_mobile_enabled_ = false; - web_view_impl_->SetDefaultPageScaleLimits( + web_view_->SetDefaultPageScaleLimits( original_default_minimum_page_scale_factor_, original_default_maximum_page_scale_factor_); // mainFrameImpl() could be null during cleanup or remote <-> local swap. - if (web_view_impl_->MainFrameImpl()) - web_view_impl_->MainFrameImpl()->GetFrameView()->UpdateLayout(); + if (web_view_->MainFrameImpl()) + web_view_->MainFrameImpl()->GetFrameView()->UpdateLayout(); } float DevToolsEmulator::CompositorDeviceScaleFactor() const { if (device_metrics_enabled_) return emulation_params_.device_scale_factor; - return web_view_impl_->GetPage()->DeviceScaleFactorDeprecated(); + return web_view_->GetPage()->DeviceScaleFactorDeprecated(); } void DevToolsEmulator::ForceViewport(const WebFloatPoint& position, float scale) { GraphicsLayer* container_layer = - web_view_impl_->GetPage()->GetVisualViewport().ContainerLayer(); + web_view_->GetPage()->GetVisualViewport().ContainerLayer(); if (!viewport_override_) { viewport_override_ = ViewportOverride(); @@ -397,7 +392,7 @@ viewport_override_ = WTF::nullopt; GraphicsLayer* container_layer = - web_view_impl_->GetPage()->GetVisualViewport().ContainerLayer(); + web_view_->GetPage()->GetVisualViewport().ContainerLayer(); if (container_layer) container_layer->SetMasksToBounds(original_masking); UpdateRootLayerTransform(); @@ -417,13 +412,15 @@ // Scale first, so that translation is unaffected. transform->Translate(offset.width, offset.height); transform->Scale(emulation_params_.scale); - if (web_view_impl_->MainFrameImpl()) - web_view_impl_->MainFrameImpl()->SetInputEventsTransformForEmulation( + if (web_view_->MainFrameImpl()) { + web_view_->MainFrameImpl()->SetInputEventsTransformForEmulation( offset, emulation_params_.scale); + } } else { - if (web_view_impl_->MainFrameImpl()) - web_view_impl_->MainFrameImpl()->SetInputEventsTransformForEmulation( + if (web_view_->MainFrameImpl()) { + web_view_->MainFrameImpl()->SetInputEventsTransformForEmulation( WebSize(0, 0), 1.0); + } } } @@ -436,8 +433,8 @@ transform->Scale(viewport_override_->scale); // Translate while taking into account current scroll offset. - WebSize scroll_offset = web_view_impl_->MainFrame()->GetScrollOffset(); - WebFloatPoint visual_offset = web_view_impl_->VisualViewportOffset(); + WebSize scroll_offset = web_view_->MainFrame()->GetScrollOffset(); + WebFloatPoint visual_offset = web_view_->VisualViewportOffset(); float scroll_x = scroll_offset.width + visual_offset.x; float scroll_y = scroll_offset.height + visual_offset.y; transform->Translate(-viewport_override_->position.x + scroll_x, @@ -445,7 +442,7 @@ // First, reverse page scale, so we don't have to take it into account for // calculation of the translation. - transform->Scale(1. / web_view_impl_->PageScaleFactor()); + transform->Scale(1. / web_view_->PageScaleFactor()); } void DevToolsEmulator::UpdateRootLayerTransform() { @@ -455,13 +452,13 @@ // viewport override. ApplyViewportOverride(&transform); ApplyDeviceEmulationTransform(&transform); - web_view_impl_->SetDeviceEmulationTransform(transform); + web_view_->SetDeviceEmulationTransform(transform); } WTF::Optional<IntRect> DevToolsEmulator::VisibleContentRectForPainting() const { if (!viewport_override_) return WTF::nullopt; - FloatSize viewport_size(web_view_impl_->LayerTreeView()->GetViewportSize()); + FloatSize viewport_size(web_view_->LayerTreeView()->GetViewportSize()); viewport_size.Scale(1. / CompositorDeviceScaleFactor()); viewport_size.Scale(1. / viewport_override_->scale); return EnclosingIntRect( @@ -476,23 +473,23 @@ original_touch_event_feature_detection_enabled_ = RuntimeEnabledFeatures::touchEventFeatureDetectionEnabled(); original_device_supports_touch_ = - web_view_impl_->GetPage()->GetSettings().GetDeviceSupportsTouch(); + web_view_->GetPage()->GetSettings().GetDeviceSupportsTouch(); original_max_touch_points_ = - web_view_impl_->GetPage()->GetSettings().GetMaxTouchPoints(); + web_view_->GetPage()->GetSettings().GetMaxTouchPoints(); } RuntimeEnabledFeatures::setTouchEventFeatureDetectionEnabled( enabled ? true : original_touch_event_feature_detection_enabled_); if (!original_device_supports_touch_) { - if (enabled && web_view_impl_->MainFrameImpl()) { - web_view_impl_->MainFrameImpl() + if (enabled && web_view_->MainFrameImpl()) { + web_view_->MainFrameImpl() ->GetFrame() ->GetEventHandler() .ClearMouseEventManager(); } - web_view_impl_->GetPage()->GetSettings().SetDeviceSupportsTouch( + web_view_->GetPage()->GetSettings().SetDeviceSupportsTouch( enabled ? true : original_device_supports_touch_); // Currently emulation does not provide multiple touch points. - web_view_impl_->GetPage()->GetSettings().SetMaxTouchPoints( + web_view_->GetPage()->GetSettings().SetMaxTouchPoints( enabled ? 1 : original_max_touch_points_); } touch_event_emulation_enabled_ = enabled; @@ -502,19 +499,19 @@ // fails during remote -> local main frame transition. // We should instead route emulation from browser through the WebViewImpl // to the local main frame, and remove InspectorEmulationAgent entirely. - if (web_view_impl_->MainFrameImpl()) - web_view_impl_->MainFrameImpl()->GetFrameView()->UpdateLayout(); + if (web_view_->MainFrameImpl()) + web_view_->MainFrameImpl()->GetFrameView()->UpdateLayout(); } void DevToolsEmulator::SetScriptExecutionDisabled( bool script_execution_disabled) { script_execution_disabled_ = script_execution_disabled; - web_view_impl_->GetPage()->GetSettings().SetScriptEnabled( + web_view_->GetPage()->GetSettings().SetScriptEnabled( script_execution_disabled_ ? false : embedder_script_enabled_); } bool DevToolsEmulator::HandleInputEvent(const WebInputEvent& input_event) { - Page* page = web_view_impl_->GetPage(); + Page* page = web_view_->GetPage(); if (!page) return false; @@ -542,8 +539,8 @@ float new_page_scale_factor = page_scale_factor * scaled_event.PinchScale(); IntPoint anchor_css(*last_pinch_anchor_dip_.get()); anchor_css.Scale(1.f / new_page_scale_factor, 1.f / new_page_scale_factor); - web_view_impl_->SetPageScaleFactor(new_page_scale_factor); - web_view_impl_->MainFrame()->SetScrollOffset( + web_view_->SetPageScaleFactor(new_page_scale_factor); + web_view_->MainFrame()->SetScrollOffset( ToIntSize(*last_pinch_anchor_css_.get() - ToIntSize(anchor_css))); } if (scaled_event.GetType() == WebInputEvent::kGesturePinchEnd) {
diff --git a/third_party/WebKit/Source/web/DevToolsEmulator.h b/third_party/WebKit/Source/core/inspector/DevToolsEmulator.h similarity index 97% rename from third_party/WebKit/Source/web/DevToolsEmulator.h rename to third_party/WebKit/Source/core/inspector/DevToolsEmulator.h index b8c738f5..f7120a0 100644 --- a/third_party/WebKit/Source/web/DevToolsEmulator.h +++ b/third_party/WebKit/Source/core/inspector/DevToolsEmulator.h
@@ -6,6 +6,7 @@ #define DevToolsEmulator_h #include <memory> +#include "core/CoreExport.h" #include "platform/heap/Handle.h" #include "platform/wtf/Forward.h" #include "platform/wtf/Optional.h" @@ -13,7 +14,6 @@ #include "public/platform/WebFloatPoint.h" #include "public/platform/WebViewportStyle.h" #include "public/web/WebDeviceEmulationParams.h" -#include "web/WebExport.h" namespace blink { @@ -23,7 +23,7 @@ class WebInputEvent; class WebViewBase; -class WEB_EXPORT DevToolsEmulator final +class CORE_EXPORT DevToolsEmulator final : public GarbageCollectedFinalized<DevToolsEmulator> { public: ~DevToolsEmulator(); @@ -78,7 +78,7 @@ void ApplyViewportOverride(TransformationMatrix*); void UpdateRootLayerTransform(); - WebViewBase* web_view_impl_; + WebViewBase* web_view_; bool device_metrics_enabled_; bool emulate_mobile_enabled_;
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp index 3b785c0..e1f1693 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
@@ -556,18 +556,6 @@ AddSelfVisualOverflow(LayoutRect(inflated_rect)); } -DISABLE_CFI_PERF -bool LayoutBlock::CreatesNewFormattingContext() const { - return IsInlineBlockOrInlineTable() || IsFloatingOrOutOfFlowPositioned() || - HasOverflowClip() || IsFlexItemIncludingDeprecated() || - Style()->SpecifiesColumns() || IsLayoutFlowThread() || IsTableCell() || - IsTableCaption() || IsFieldset() || IsWritingModeRoot() || - IsDocumentElement() || IsGridItem() || - Style()->GetColumnSpan() == kColumnSpanAll || - Style()->ContainsPaint() || Style()->ContainsLayout() || - IsSVGForeignObject() || Style()->Display() == EDisplay::kFlowRoot; -} - static inline bool ChangeInAvailableLogicalHeightAffectsChild( LayoutBlock* parent, LayoutBox& child) {
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.h b/third_party/WebKit/Source/core/layout/LayoutBlock.h index e15f132..50fe207 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlock.h +++ b/third_party/WebKit/Source/core/layout/LayoutBlock.h
@@ -137,7 +137,7 @@ LayoutUnit MinLineHeightForReplacedObject(bool is_first_line, LayoutUnit replaced_height) const; - bool CreatesNewFormattingContext() const; + virtual bool CreatesNewFormattingContext() const { return true; } const char* GetName() const override; @@ -471,8 +471,6 @@ // Returns true if the positioned movement-only layout succeeded. bool TryLayoutDoingPositionedMovementOnly(); - bool AvoidsFloats() const override { return true; } - bool IsInSelfHitTestingPhase(HitTestAction hit_test_action) const final { return hit_test_action == kHitTestBlockBackground || hit_test_action == kHitTestChildBlockBackground;
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp index c8863f9..b649fd8 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -4246,13 +4246,72 @@ DetermineLogicalLeftPositionForChild(spanner); } +DISABLE_CFI_PERF +bool LayoutBlockFlow::CreatesNewFormattingContext() const { + if (IsInline() || IsFloatingOrOutOfFlowPositioned() || HasOverflowClip() || + IsFlexItemIncludingDeprecated() || IsTableCell() || IsTableCaption() || + IsFieldset() || IsDocumentElement() || IsGridItem() || + IsWritingModeRoot() || Style()->Display() == EDisplay::kFlowRoot || + Style()->ContainsPaint() || Style()->ContainsLayout() || + Style()->SpecifiesColumns() || + Style()->GetColumnSpan() == kColumnSpanAll) { + // The specs require this object to establish a new formatting context. + return true; + } + + // The remaining checks here are not covered by any spec, but we still need to + // establish new formatting contexts in some cases, for various reasons. + + if (IsRubyText()) { + // Ruby text objects are pushed around after layout, to become flush with + // the associated ruby base. As such, we cannot let floats leak out from + // ruby text objects. + return true; + } + + if (IsLayoutFlowThread()) { + // The spec requires multicol containers to establish new formatting + // contexts. Blink uses an anonymous flow thread child of the multicol + // container to actually perform layout inside. Therefore we need to + // propagate the BFCness down to the flow thread, so that floats are fully + // contained by the flow thread, and thereby the multicol container. + return true; + } + + if (IsHR()) { + // Not mentioned in the spec, but we want HR elements to be pushed to the + // side by floats (and all engines seem to do that), since we use borders to + // render HR (and it would just ugly to let those borders be painted under + // the float). + return true; + } + + if (IsLegend()) { + // This is wrong; see crbug.com/727378 . It may be that our current + // implementation requires the rendered legend inside a FIELDSET to create a + // new formatting context. That should probably be fixed too, but more + // importantly: We should never create a new formatting context for LEGEND + // elements that aren't associated with a FIELDSET. + return true; + } + + if (IsTextControl()) { + // INPUT and other replaced elements rendered by Blink itself should be + // completely contained. + return true; + } + + if (IsSVGForeignObject()) { + // This is the root of a foreign object. Don't let anything inside it escape + // to our ancestors. + return true; + } + + return false; +} + bool LayoutBlockFlow::AvoidsFloats() const { - // Floats can't intrude into our box if we have a non-auto column count or - // width. - // Note: we need to use LayoutBox::avoidsFloats here since - // LayoutBlock::avoidsFloats is always true. - return LayoutBox::AvoidsFloats() || !Style()->HasAutoColumnCount() || - !Style()->HasAutoColumnWidth(); + return ShouldBeConsideredAsReplaced() || CreatesNewFormattingContext(); } void LayoutBlockFlow::MoveChildrenTo(LayoutBoxModelObject* to_box_model_object,
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h index 3950925..4c055f9 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h +++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
@@ -321,7 +321,8 @@ void PositionSpannerDescendant(LayoutMultiColumnSpannerPlaceholder& child); - bool AvoidsFloats() const override; + bool CreatesNewFormattingContext() const override; + bool AvoidsFloats() const final; using LayoutBoxModelObject::MoveChildrenTo; void MoveChildrenTo(LayoutBoxModelObject* to_box_model_object,
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp index 8cbc40d..a082d693 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -4907,14 +4907,8 @@ isHTMLImageElement(ToElement(node))); } -DISABLE_CFI_PERF bool LayoutBox::AvoidsFloats() const { - // crbug.com/460704: This should be merged with createsNewFormattingContext(). - return ShouldBeConsideredAsReplaced() || HasOverflowClip() || IsHR() || - IsLegend() || IsWritingModeRoot() || IsFlexItemIncludingDeprecated() || - Style()->GetColumnSpan() == kColumnSpanAll || - Style()->ContainsPaint() || Style()->ContainsLayout() || - Style()->Display() == EDisplay::kFlowRoot; + return true; } bool LayoutBox::HasNonCompositedScrollbars() const {
diff --git a/third_party/WebKit/Source/core/layout/LayoutFieldset.h b/third_party/WebKit/Source/core/layout/LayoutFieldset.h index f5a33c2e..26b243f 100644 --- a/third_party/WebKit/Source/core/layout/LayoutFieldset.h +++ b/third_party/WebKit/Source/core/layout/LayoutFieldset.h
@@ -45,7 +45,6 @@ SubtreeLayoutScope&) override; void ComputePreferredLogicalWidths() override; - bool AvoidsFloats() const override { return true; } void PaintBoxDecorationBackground(const PaintInfo&, const LayoutPoint&) const override;
diff --git a/third_party/WebKit/Source/core/layout/LayoutRubyText.cpp b/third_party/WebKit/Source/core/layout/LayoutRubyText.cpp index 508d3cb..6d259a8 100644 --- a/third_party/WebKit/Source/core/layout/LayoutRubyText.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutRubyText.cpp
@@ -79,8 +79,4 @@ logical_width -= inset; } -bool LayoutRubyText::AvoidsFloats() const { - return true; -} - } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutRubyText.h b/third_party/WebKit/Source/core/layout/LayoutRubyText.h index c6dbaed..db5de6b 100644 --- a/third_party/WebKit/Source/core/layout/LayoutRubyText.h +++ b/third_party/WebKit/Source/core/layout/LayoutRubyText.h
@@ -49,8 +49,6 @@ bool IsChildAllowed(LayoutObject*, const ComputedStyle&) const override; private: - bool AvoidsFloats() const override; - ETextAlign TextAlignmentForLine(bool ends_with_soft_break) const override; void AdjustInlineDirectionLineBounds( unsigned expansion_opportunity_count,
diff --git a/third_party/WebKit/Source/core/layout/LayoutTextControl.h b/third_party/WebKit/Source/core/layout/LayoutTextControl.h index 0a19aa4..aec8b8e 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTextControl.h +++ b/third_party/WebKit/Source/core/layout/LayoutTextControl.h
@@ -95,7 +95,6 @@ LayoutUnit& max_logical_width) const final; void ComputePreferredLogicalWidths() final; void RemoveLeftoverAnonymousBlock(LayoutBlock*) final {} - bool AvoidsFloats() const final { return true; } void AddOutlineRects(Vector<LayoutRect>&, const LayoutPoint& additional_offset,
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc index f9b7422..fb30678 100644 --- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc +++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -232,8 +232,7 @@ // Place items from line-left to line-right along with the baseline. // Items are already bidi-reordered to the visual order. - LayoutUnit line_left_position = LogicalLeftOffset(); - LayoutUnit position = line_left_position; + LayoutUnit position; for (auto& item_result : *line_items) { const NGInlineItem& item = items[item_result.item_index]; @@ -327,19 +326,14 @@ // the line box to the line top. line_box.MoveChildrenInBlockDirection(baseline); - DCHECK_EQ(line_left_position, LogicalLeftOffset()); - LayoutUnit inline_size = position - line_left_position; + LayoutUnit inline_size = position; + NGLogicalOffset offset(LogicalLeftOffset(), + baseline - box_states_.LineBoxState().metrics.ascent); + ApplyTextAlign(&offset.inline_offset, inline_size, + current_opportunity_.size.inline_size); + line_box.SetInlineSize(inline_size); - - // Account for text align property. - if (Node()->Style().GetTextAlign() == ETextAlign::kRight) { - line_box.MoveChildrenInInlineDirection( - current_opportunity_.size.inline_size - inline_size); - } - - container_builder_.AddChild( - line_box.ToLineBoxFragment(), - {LayoutUnit(), baseline - box_states_.LineBoxState().metrics.ascent}); + container_builder_.AddChild(line_box.ToLineBoxFragment(), offset); max_inline_size_ = std::max(max_inline_size_, inline_size); content_size_ = line_bottom; @@ -397,6 +391,29 @@ LayoutUnit(0)); } +void NGInlineLayoutAlgorithm::ApplyTextAlign(LayoutUnit* line_left, + LayoutUnit inline_size, + LayoutUnit available_width) { + // TODO(kojii): Implement text-align-last. + ETextAlign text_align = LineStyle().GetTextAlign(); + switch (text_align) { + case ETextAlign::kRight: + case ETextAlign::kWebkitRight: + // Wide lines spill out of the block based off direction. + // So even if text-align is right, if direction is LTR, wide lines should + // overflow out of the right side of the block. + // TODO(kojii): Investigate how to handle trailing spaces. + if (inline_size < available_width || + !LineStyle().IsLeftToRightDirection()) + *line_left += available_width - inline_size; + break; + default: + // TODO(layout-dev): Implement. + // Refer to LayoutBlockFlow::UpdateLogicalWidthForAlignment(). + break; + } +} + void NGInlineLayoutAlgorithm::FindNextLayoutOpportunity() { NGLogicalOffset iter_offset = ConstraintSpace().BfcOffset(); if (container_builder_.BfcOffset()) {
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h index 7e9e601c..6e211718 100644 --- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h +++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h
@@ -75,6 +75,10 @@ NGLineBoxFragmentBuilder*, NGTextFragmentBuilder*); + void ApplyTextAlign(LayoutUnit* line_left, + LayoutUnit inline_size, + LayoutUnit available_width); + // Finds the next layout opportunity for the next text fragment. void FindNextLayoutOpportunity();
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc index d194c89..45b6776 100644 --- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc +++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc
@@ -155,12 +155,9 @@ ToNGPhysicalBoxFragment(container_fragment->Children()[0].Get()); auto* line_box_fragments_wrapper = ToNGPhysicalBoxFragment(span_box_fragments_wrapper->Children()[0].Get()); - Vector<NGPhysicalTextFragment*> text_fragments; + Vector<NGPhysicalLineBoxFragment*> line_boxes; for (const auto& child : line_box_fragments_wrapper->Children()) { - auto* line_box = ToNGPhysicalLineBoxFragment(child.Get()); - EXPECT_EQ(1u, line_box->Children().size()); - for (const auto& text : line_box->Children()) - text_fragments.push_back(ToNGPhysicalTextFragment(text.Get())); + line_boxes.push_back(ToNGPhysicalLineBoxFragment(child.Get())); } LayoutText* layout_text = @@ -170,22 +167,22 @@ // Line break points may vary by minor differences in fonts. // The test is valid as long as we have 3 or more lines and their positions // are correct. - EXPECT_GE(text_fragments.size(), 3UL); + EXPECT_GE(line_boxes.size(), 3UL); - auto* text_fragment1 = text_fragments[0]; + auto* line_box1 = line_boxes[0]; // 40 = #left-float1' width 30 + #left-float2 10 - EXPECT_EQ(LayoutUnit(40), text_fragment1->Offset().left); + EXPECT_EQ(LayoutUnit(40), line_box1->Offset().left); InlineTextBox* inline_text_box1 = layout_text->FirstTextBox(); EXPECT_EQ(LayoutUnit(40), inline_text_box1->X()); - auto* text_fragment2 = text_fragments[1]; + auto* line_box2 = line_boxes[1]; // 40 = #left-float1' width 30 - EXPECT_EQ(LayoutUnit(30), text_fragment2->Offset().left); + EXPECT_EQ(LayoutUnit(30), line_box2->Offset().left); InlineTextBox* inline_text_box2 = inline_text_box1->NextTextBox(); EXPECT_EQ(LayoutUnit(30), inline_text_box2->X()); - auto* text_fragment3 = text_fragments[2]; - EXPECT_EQ(LayoutUnit(), text_fragment3->Offset().left); + auto* line_box3 = line_boxes[2]; + EXPECT_EQ(LayoutUnit(), line_box3->Offset().left); InlineTextBox* inline_text_box3 = inline_text_box2->NextTextBox(); EXPECT_EQ(LayoutUnit(), inline_text_box3->X()); }
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc index 31440806..50d4bd0 100644 --- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc +++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc
@@ -425,11 +425,13 @@ for (const auto& container_child : box_fragment->Children()) { NGPhysicalLineBoxFragment* physical_line_box = ToNGPhysicalLineBoxFragment(container_child.Get()); + NGLineBoxFragment line_box(constraint_space.WritingMode(), + physical_line_box); // Create a BidiRunList for this line. CreateBidiRuns(&bidi_runs, physical_line_box->Children(), constraint_space, - NGLogicalOffset(), items, text_offsets, - &positions_for_bidi_runs, &positions); + {line_box.InlineOffset(), LayoutUnit(0)}, items, + text_offsets, &positions_for_bidi_runs, &positions); // TODO(kojii): bidi needs to find the logical last run. bidi_runs.SetLogicallyLastRun(bidi_runs.LastRun()); @@ -444,8 +446,7 @@ PlaceInlineBoxChildren(root_line_box, positions_for_bidi_runs, positions); // Copy to RootInlineBox. - NGLineBoxFragment line_box(constraint_space.WritingMode(), - physical_line_box); + root_line_box->SetLogicalLeft(line_box.InlineOffset()); root_line_box->SetLogicalWidth(line_box.InlineSize()); LayoutUnit line_top = line_box.BlockOffset(); NGLineHeightMetrics line_metrics(Style(), baseline_type);
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_box_fragment_builder.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_box_fragment_builder.cc index b7da848..6def2c7 100644 --- a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_box_fragment_builder.cc +++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_box_fragment_builder.cc
@@ -50,18 +50,6 @@ offset.block_offset += delta; } -void NGLineBoxFragmentBuilder::MoveChildrenInInlineDirection(LayoutUnit delta) { - NGWritingMode writing_mode( - FromPlatformWritingMode(node_->Style().GetWritingMode())); - LayoutUnit child_inline_size; - for (size_t i = 0; i < children_.size(); ++i) { - offsets_[i].inline_offset = delta + child_inline_size; - NGPhysicalFragment* child = children_[i].Get(); - child_inline_size += - child->Size().ConvertToLogical(writing_mode).inline_size; - } -} - void NGLineBoxFragmentBuilder::MoveChildrenInBlockDirection(LayoutUnit delta, unsigned start, unsigned end) {
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_box_fragment_builder.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_box_fragment_builder.h index aa09de1..cc9ae0ca 100644 --- a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_box_fragment_builder.h +++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_box_fragment_builder.h
@@ -34,8 +34,6 @@ void MoveChildrenInBlockDirection(LayoutUnit); void MoveChildrenInBlockDirection(LayoutUnit, unsigned start, unsigned end); - void MoveChildrenInInlineDirection(LayoutUnit delta); - const Vector<RefPtr<NGPhysicalFragment>>& Children() const { return children_; }
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp index 3c0095486..328a072 100644 --- a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp +++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
@@ -77,6 +77,7 @@ #include "platform/loader/fetch/ResourceTimingInfo.h" #include "platform/loader/fetch/UniqueIdentifier.h" #include "platform/mhtml/MHTMLArchive.h" +#include "platform/scheduler/child/web_scheduler.h" #include "platform/scheduler/renderer/web_view_scheduler.h" #include "platform/weborigin/SchemeRegistry.h" #include "platform/wtf/Vector.h" @@ -831,7 +832,17 @@ std::unique_ptr<WebURLLoader> FrameFetchContext::CreateURLLoader( const ResourceRequest& request) { auto loader = GetFrame()->CreateURLLoader(); - loader->SetLoadingTaskRunner(GetTaskRunner().Get()); + RefPtr<WebTaskRunner> task_runner; + + if (request.GetKeepalive()) { + // The loader should be able to work after the frame destruction, so we + // cannot use the task runner associated with the frame. + task_runner = + Platform::Current()->CurrentThread()->Scheduler()->LoadingTaskRunner(); + } else { + task_runner = GetTaskRunner(); + } + loader->SetLoadingTaskRunner(task_runner.Get()); return loader; }
diff --git a/third_party/WebKit/Source/core/loader/PingLoader.cpp b/third_party/WebKit/Source/core/loader/PingLoader.cpp index 132141c..293fe8b 100644 --- a/third_party/WebKit/Source/core/loader/PingLoader.cpp +++ b/third_party/WebKit/Source/core/loader/PingLoader.cpp
@@ -61,7 +61,6 @@ #include "platform/loader/fetch/UniqueIdentifier.h" #include "platform/network/EncodedFormData.h" #include "platform/network/ParsedContentType.h" -#include "platform/scheduler/child/web_scheduler.h" #include "platform/weborigin/SecurityOrigin.h" #include "platform/weborigin/SecurityPolicy.h" #include "platform/wtf/Compiler.h" @@ -270,8 +269,6 @@ frame->FrameScheduler()->DidStopLoading(identifier_); loader_ = fetch_context.CreateURLLoader(request); - loader_->SetLoadingTaskRunner( - Platform::Current()->CurrentThread()->Scheduler()->LoadingTaskRunner()); DCHECK(loader_); WrappedResourceRequest wrapped_request(request); wrapped_request.SetAllowStoredCredentials(credentials_allowed == @@ -414,6 +411,7 @@ ResourceRequest& request, const AtomicString& initiator, StoredCredentials credentials_allowed) { + request.SetKeepalive(true); if (MixedContentChecker::ShouldBlockFetch(frame, request, request.Url())) return false;
diff --git a/third_party/WebKit/Source/devtools/BUILD.gn b/third_party/WebKit/Source/devtools/BUILD.gn index 98f59d6..54af3f8 100644 --- a/third_party/WebKit/Source/devtools/BUILD.gn +++ b/third_party/WebKit/Source/devtools/BUILD.gn
@@ -615,6 +615,7 @@ "front_end/timeline_model/TracingLayerTree.js", "front_end/timeline/CountersGraph.js", "front_end/timeline/EventsTimelineTreeView.js", + "front_end/timeline/historyToolbarButton.css", "front_end/timeline/invalidationsTree.css", "front_end/timeline/module.json", "front_end/timeline/PerformanceModel.js", @@ -626,6 +627,8 @@ "front_end/timeline/TimelineFlameChartNetworkDataProvider.js", "front_end/timeline/timelineFlamechartPopover.css", "front_end/timeline/TimelineFlameChartView.js", + "front_end/timeline/timelineHistoryManager.css", + "front_end/timeline/TimelineHistoryManager.js", "front_end/timeline/TimelineLayersView.js", "front_end/timeline/TimelineLoader.js", "front_end/timeline/timelinePaintProfiler.css",
diff --git a/third_party/WebKit/Source/devtools/front_end/audits/AuditRules.js b/third_party/WebKit/Source/devtools/front_end/audits/AuditRules.js index 5a8ddfc..e1c2f58 100644 --- a/third_party/WebKit/Source/devtools/front_end/audits/AuditRules.js +++ b/third_party/WebKit/Source/devtools/front_end/audits/AuditRules.js
@@ -1317,7 +1317,7 @@ const nonDataUrls = requests.map(r => r.url()).filter(url => url && url.asParsedURL()); var cookieModel = target.model(SDK.CookieModel); if (cookieModel) - cookieModel.getCookiesAsync(nonDataUrls, resultCallback); + cookieModel.getCookies(nonDataUrls).then(resultCallback); else callback(result); }
diff --git a/third_party/WebKit/Source/devtools/front_end/common/Settings.js b/third_party/WebKit/Source/devtools/front_end/common/Settings.js index 794630a2..2b9a115 100644 --- a/third_party/WebKit/Source/devtools/front_end/common/Settings.js +++ b/third_party/WebKit/Source/devtools/front_end/common/Settings.js
@@ -75,6 +75,7 @@ this.createSetting(settingName, defaultValue, storageType); if (descriptor['title']) setting.setTitle(descriptor['title']); + setting._extension = extension; this._moduleSettings.set(settingName, setting); } @@ -263,6 +264,7 @@ this._storage = storage; /** @type {string} */ this._title = ''; + this._extension = null; } /** @@ -342,6 +344,13 @@ } /** + * @return {?Runtime.Extension} + */ + extension() { + return this._extension; + } + + /** * @param {string} message * @param {string} name * @param {string} value
diff --git a/third_party/WebKit/Source/devtools/front_end/console/ConsoleContextSelector.js b/third_party/WebKit/Source/devtools/front_end/console/ConsoleContextSelector.js index 673b08a..f6e003f 100644 --- a/third_party/WebKit/Source/devtools/front_end/console/ConsoleContextSelector.js +++ b/third_party/WebKit/Source/devtools/front_end/console/ConsoleContextSelector.js
@@ -24,7 +24,6 @@ this._glassPane.setPointerEventsBehavior(UI.GlassPane.PointerEventsBehavior.BlockedByGlassPane); this._list = new UI.ListControl(this, UI.ListMode.EqualHeightItems); this._list.element.classList.add('context-list'); - this._list.element.tabIndex = -1; this._rowHeight = 36; UI.createShadowRootWithCoreStyles(this._glassPane.contentElement, 'console/consoleContextSelector.css') .appendChild(this._list.element);
diff --git a/third_party/WebKit/Source/devtools/front_end/cookie_table/CookiesTable.js b/third_party/WebKit/Source/devtools/front_end/cookie_table/CookiesTable.js index cf40902..9318cc9 100644 --- a/third_party/WebKit/Source/devtools/front_end/cookie_table/CookiesTable.js +++ b/third_party/WebKit/Source/devtools/front_end/cookie_table/CookiesTable.js
@@ -33,7 +33,7 @@ */ CookieTable.CookiesTable = class extends UI.VBox { /** - * @param {function(!SDK.Cookie, ?SDK.Cookie, function(?string))=} saveCallback + * @param {function(!SDK.Cookie, ?SDK.Cookie): !Promise<boolean>=} saveCallback * @param {function()=} refreshCallback * @param {function()=} selectedCallback * @param {function(!SDK.Cookie, function())=} deleteCallback @@ -414,8 +414,8 @@ var oldCookie = node.cookie; var newCookie = this._createCookieFromData(node.data); node.cookie = newCookie; - this._saveCallback(newCookie, oldCookie, error => { - if (!error) + this._saveCallback(newCookie, oldCookie).then(success => { + if (success) this._refresh(); else node.setDirty(true);
diff --git a/third_party/WebKit/Source/devtools/front_end/main/Main.js b/third_party/WebKit/Source/devtools/front_end/main/Main.js index aa05ff9..770a33f 100644 --- a/third_party/WebKit/Source/devtools/front_end/main/Main.js +++ b/third_party/WebKit/Source/devtools/front_end/main/Main.js
@@ -113,6 +113,7 @@ Runtime.experiments.register('timelineEventInitiators', 'Timeline: event initiators'); Runtime.experiments.register('timelineFlowEvents', 'Timeline: flow events', true); Runtime.experiments.register('timelineInvalidationTracking', 'Timeline: invalidation tracking', true); + Runtime.experiments.register('timelineKeepHistory', 'Timeline: keep recording history'); Runtime.experiments.register('timelineMultipleMainViews', 'Timeline: multiple main views'); Runtime.experiments.register('timelinePaintTimingMarkers', 'Timeline: paint timing markers', true); Runtime.experiments.register('timelinePerFrameTrack', 'Timeline: per-frame tracks', true);
diff --git a/third_party/WebKit/Source/devtools/front_end/main/RenderingOptions.js b/third_party/WebKit/Source/devtools/front_end/main/RenderingOptions.js index f3e8102..aa6b17b7 100644 --- a/third_party/WebKit/Source/devtools/front_end/main/RenderingOptions.js +++ b/third_party/WebKit/Source/devtools/front_end/main/RenderingOptions.js
@@ -28,9 +28,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/** - * @implements {SDK.SDKModelObserver<!SDK.EmulationModel>} - */ Main.RenderingOptionsView = class extends UI.VBox { constructor() { super(true); @@ -54,20 +51,14 @@ Common.moduleSetting('showScrollBottleneckRects')); this.contentElement.createChild('div').classList.add('panel-section-separator'); - var cssMediaSubtitle = Common.UIString('Forces media type for testing print and screen styles'); - var checkboxLabel = UI.CheckboxLabel.create(Common.UIString('Emulate CSS Media'), false, cssMediaSubtitle); - this._mediaCheckbox = checkboxLabel.checkboxElement; - this._mediaCheckbox.addEventListener('click', this._mediaToggled.bind(this), false); - this.contentElement.appendChild(checkboxLabel); - - var mediaRow = this.contentElement.createChild('div', 'media-row'); - this._mediaSelect = mediaRow.createChild('select', 'chrome-select'); - this._mediaSelect.appendChild(new Option(Common.UIString('print'), 'print')); - this._mediaSelect.appendChild(new Option(Common.UIString('screen'), 'screen')); - this._mediaSelect.addEventListener('change', this._mediaToggled.bind(this), false); - this._mediaSelect.disabled = true; - - SDK.targetManager.observeModels(SDK.EmulationModel, this); + var mediaSetting = Common.moduleSetting('emulatedCSSMedia'); + var mediaSelect = UI.SettingsUI.createControlForSetting(mediaSetting); + if (mediaSelect) { + var mediaRow = this.contentElement.createChild('span', 'media-row'); + mediaRow.createChild('label').textContent = Common.UIString('Emulate CSS Media'); + mediaRow.createChild('p').textContent = Common.UIString('Forces media type for testing print and screen styles'); + mediaRow.appendChild(mediaSelect); + } } /** @@ -80,27 +71,4 @@ UI.SettingsUI.bindCheckbox(checkboxLabel.checkboxElement, setting); this.contentElement.appendChild(checkboxLabel); } - - /** - * @override - * @param {!SDK.EmulationModel} emulationModel - */ - modelAdded(emulationModel) { - if (this._mediaCheckbox.checked) - emulationModel.emulateCSSMedia(this._mediaSelect.value); - } - - _mediaToggled() { - this._mediaSelect.disabled = !this._mediaCheckbox.checked; - var media = this._mediaCheckbox.checked ? this._mediaSelect.value : null; - for (var emulationModel of SDK.targetManager.models(SDK.EmulationModel)) - emulationModel.emulateCSSMedia(media); - } - - /** - * @override - * @param {!SDK.EmulationModel} emulationModel - */ - modelRemoved(emulationModel) { - } };
diff --git a/third_party/WebKit/Source/devtools/front_end/main/renderingOptions.css b/third_party/WebKit/Source/devtools/front_end/main/renderingOptions.css index 3c79830d..77eeb51 100644 --- a/third_party/WebKit/Source/devtools/front_end/main/renderingOptions.css +++ b/third_party/WebKit/Source/devtools/front_end/main/renderingOptions.css
@@ -14,7 +14,13 @@ } .media-row { - margin-left: 25px; + margin-left: 22px; + flex: none; +} + +.media-row p { + margin-top: 0; + color: gray; } .panel-section-separator {
diff --git a/third_party/WebKit/Source/devtools/front_end/perf_ui/TimelineOverviewPane.js b/third_party/WebKit/Source/devtools/front_end/perf_ui/TimelineOverviewPane.js index b175fba..06d08c8 100644 --- a/third_party/WebKit/Source/devtools/front_end/perf_ui/TimelineOverviewPane.js +++ b/third_party/WebKit/Source/devtools/front_end/perf_ui/TimelineOverviewPane.js
@@ -159,7 +159,6 @@ this._overviewCalculator.setDisplayWidth(this._overviewGrid.clientWidth()); for (var i = 0; i < this._overviewControls.length; ++i) this._overviewControls[i].update(); - this._overviewGrid.updateDividers(this._overviewCalculator); this._updateMarkers(); this._updateWindow(); } @@ -169,7 +168,6 @@ */ setMarkers(markers) { this._markers = markers; - this._updateMarkers(); } _updateMarkers() { @@ -467,8 +465,17 @@ } resetCanvas() { - this._canvas.width = this.element.clientWidth * window.devicePixelRatio; - this._canvas.height = this.element.clientHeight * window.devicePixelRatio; + if (this.element.clientWidth) + this.setCanvasSize(this.element.clientWidth, this.element.clientHeight); + } + + /** + * @param {number} width + * @param {number} height + */ + setCanvasSize(width, height) { + this._canvas.width = width * window.devicePixelRatio; + this._canvas.height = height * window.devicePixelRatio; } };
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/CookieItemsView.js b/third_party/WebKit/Source/devtools/front_end/resources/CookieItemsView.js index 9fd25526..1735eb5 100644 --- a/third_party/WebKit/Source/devtools/front_end/resources/CookieItemsView.js +++ b/third_party/WebKit/Source/devtools/front_end/resources/CookieItemsView.js
@@ -66,16 +66,14 @@ /** * @param {!SDK.Cookie} newCookie * @param {?SDK.Cookie} oldCookie - * @param {function(?string)} callback + * @return {!Promise<boolean>} */ - _saveCookie(newCookie, oldCookie, callback) { - if (!this._model) { - callback(Common.UIString('Unable to save the cookie')); - return; - } + _saveCookie(newCookie, oldCookie) { + if (!this._model) + return Promise.resolve(false); if (oldCookie && (newCookie.name() !== oldCookie.name() || newCookie.url() !== oldCookie.url())) this._model.deleteCookie(oldCookie); - this._model.saveCookie(newCookie, callback); + return this._model.saveCookie(newCookie); } /** @@ -87,7 +85,7 @@ } /** - * @param {!Array.<!SDK.Cookie>} allCookies + * @param {!Array<!SDK.Cookie>} allCookies */ _updateWithCookies(allCookies) { this._totalSize = allCookies.reduce((size, cookie) => size + cookie.size(), 0); @@ -132,7 +130,7 @@ * @override */ refreshItems() { - this._model.getCookiesForDomain(this._cookieDomain, cookies => this._updateWithCookies(cookies)); + this._model.getCookiesForDomain(this._cookieDomain).then(this._updateWithCookies.bind(this)); } _onResponseReceived() {
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/DatabaseQueryView.js b/third_party/WebKit/Source/devtools/front_end/resources/DatabaseQueryView.js index 85ea436..40ff3b2 100644 --- a/third_party/WebKit/Source/devtools/front_end/resources/DatabaseQueryView.js +++ b/third_party/WebKit/Source/devtools/front_end/resources/DatabaseQueryView.js
@@ -135,10 +135,10 @@ _queryFinished(query, columnNames, values) { var dataGrid = DataGrid.SortableDataGrid.create(columnNames, values); - dataGrid.setStriped(true); var trimmedQuery = query.trim(); if (dataGrid) { + dataGrid.setStriped(true); dataGrid.renderInline(); this._appendViewQueryResult(trimmedQuery, dataGrid.asWidget()); dataGrid.autoSizeColumns(5);
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/DatabaseTableView.js b/third_party/WebKit/Source/devtools/front_end/resources/DatabaseTableView.js index 582edd67..733d539 100644 --- a/third_party/WebKit/Source/devtools/front_end/resources/DatabaseTableView.js +++ b/third_party/WebKit/Source/devtools/front_end/resources/DatabaseTableView.js
@@ -77,13 +77,13 @@ this.element.removeChildren(); this._dataGrid = DataGrid.SortableDataGrid.create(columnNames, values); - this._dataGrid.setStriped(true); this._visibleColumnsInput.setVisible(!!this._dataGrid); if (!this._dataGrid) { this._emptyWidget = new UI.EmptyWidget(Common.UIString('The “%s”\ntable is empty.', this.tableName)); this._emptyWidget.show(this.element); return; } + this._dataGrid.setStriped(true); this._dataGrid.asWidget().show(this.element); this._dataGrid.autoSizeColumns(5);
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBViews.js b/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBViews.js index 4fd9528..a421227 100644 --- a/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBViews.js +++ b/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBViews.js
@@ -53,6 +53,11 @@ Common.UIString('Delete database'), () => this._deleteDatabase(), Common.UIString('Delete database')); footer.appendChild(this._clearButton); + this._refreshButton = UI.createTextButton( + Common.UIString('Refresh database'), () => this._refreshDatabaseButtonClicked(), + Common.UIString('Refresh database')); + footer.appendChild(this._refreshButton); + this.update(database); } @@ -61,12 +66,21 @@ this._versionElement.textContent = this._database.version; } + _refreshDatabaseButtonClicked() { + this._model.refreshDatabase(this._database.databaseId); + } + /** * @param {!Resources.IndexedDBModel.Database} database */ update(database) { this._database = database; this._refreshDatabase(); + this._updatedForTests(); + } + + _updatedForTests() { + // Sniffed in tests. } _deleteDatabase() { @@ -289,6 +303,7 @@ this._pageBackButton.setEnabled(!!skipCount); this._pageForwardButton.setEnabled(hasMore); + this._updatedDataForTests(); } var idbKeyRange = key ? window.IDBKeyRange.lowerBound(key) : null; @@ -302,6 +317,10 @@ } } + _updatedDataForTests() { + // Sniffed in tests. + } + /** * @param {!Common.Event} event */
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CookieModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/CookieModel.js index d9d958d..c4e44da 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/CookieModel.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/CookieModel.js
@@ -59,17 +59,11 @@ /** * @param {!Array<string>} urls - * @param {function(!Array<!SDK.Cookie>)} callback + * @return {!Promise<!Array<!SDK.Cookie>>} */ - getCookiesAsync(urls, callback) { - this.target().networkAgent().getCookies(urls, (err, cookies) => { - if (err) { - console.error(err); - return callback([]); - } - - callback(cookies.map(cookie => SDK.CookieModel._parseProtocolCookie(cookie))); - }); + getCookies(urls) { + return this.target().networkAgent().getCookies(urls).then( + cookies => (cookies || []).map(cookie => SDK.CookieModel._parseProtocolCookie(cookie))); } /** @@ -85,30 +79,33 @@ * @param {function()=} callback */ clear(domain, callback) { - this.getCookiesForDomain(domain || null, cookies => this._deleteAll(cookies, callback)); + this.getCookiesForDomain(domain || null).then(cookies => this._deleteAll(cookies, callback)); } /** * @param {!SDK.Cookie} cookie - * @param {function(?Protocol.Error, boolean)} callback + * @return {!Promise<boolean>} */ - saveCookie(cookie, callback) { + saveCookie(cookie) { var domain = cookie.domain(); if (!domain.startsWith('.')) domain = ''; var expires = undefined; if (cookie.expires()) expires = Math.floor(Date.parse(cookie.expires()) / 1000); - this.target().networkAgent().setCookie( - cookie.url(), cookie.name(), cookie.value(), domain, cookie.path(), cookie.secure(), cookie.httpOnly(), - cookie.sameSite(), expires, callback); + return this.target() + .networkAgent() + .setCookie( + cookie.url(), cookie.name(), cookie.value(), domain, cookie.path(), cookie.secure(), cookie.httpOnly(), + cookie.sameSite(), expires) + .then(success => !!success); } /** * @param {?string} domain - * @param {function(!Array<!SDK.Cookie>)} callback + * @return {!Promise<!Array<!SDK.Cookie>>} */ - getCookiesForDomain(domain, callback) { + getCookiesForDomain(domain) { var resourceURLs = []; /** * @param {!SDK.Resource} resource @@ -121,7 +118,7 @@ var resourceTreeModel = this.target().model(SDK.ResourceTreeModel); if (resourceTreeModel) resourceTreeModel.forAllResources(populateResourceURLs); - this.getCookiesAsync(resourceURLs, callback); + return this.getCookies(resourceURLs); } /** @@ -130,10 +127,8 @@ */ _deleteAll(cookies, callback) { var networkAgent = this.target().networkAgent(); - function deleteCookie(cookie) { - return new Promise(resolve => networkAgent.deleteCookie(cookie.name(), cookie.url(), resolve)); - } - Promise.all(cookies.map(deleteCookie)).then(callback || function() {}); + Promise.all(cookies.map(cookie => networkAgent.deleteCookie(cookie.name(), cookie.url()))) + .then(callback || function() {}); } };
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/EmulationModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/EmulationModel.js index d006386b..4bd1c4eb 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/EmulationModel.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/EmulationModel.js
@@ -22,6 +22,11 @@ if (disableJavascriptSetting.get()) this._emulationAgent.setScriptExecutionDisabled(true); + var mediaSetting = Common.moduleSetting('emulatedCSSMedia'); + mediaSetting.addChangeListener(() => this._emulateCSSMedia(mediaSetting.get())); + if (mediaSetting.get()) + this._emulateCSSMedia(mediaSetting.get()); + this._touchEnabled = false; this._touchMobile = false; this._customTouchEnabled = false; @@ -110,10 +115,10 @@ } /** - * @param {?string} media + * @param {string} media */ - emulateCSSMedia(media) { - this._emulationAgent.setEmulatedMedia(media || ''); + _emulateCSSMedia(media) { + this._emulationAgent.setEmulatedMedia(media); if (this._cssModel) this._cssModel.mediaQueryResultChanged(); }
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/NetworkManager.js b/third_party/WebKit/Source/devtools/front_end/sdk/NetworkManager.js index 1be45dc..1d0b90c 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/NetworkManager.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/NetworkManager.js
@@ -883,19 +883,11 @@ /** * @param {string} origin - * @param {function(!Array<string>)} callback + * @return {!Promise<!Array<string>>} */ - getCertificate(origin, callback) { + getCertificate(origin) { var target = SDK.targetManager.mainTarget(); - target.networkAgent().getCertificate(origin, mycallback); - - /** - * @param {?Protocol.Error} error - * @param {!Array<string>} certificate - */ - function mycallback(error, certificate) { - callback(error ? [] : certificate); - } + return target.networkAgent().getCertificate(origin).then(certificate => certificate || []); } /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/NetworkRequest.js b/third_party/WebKit/Source/devtools/front_end/sdk/NetworkRequest.js index 4750c08..311f417 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/NetworkRequest.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/NetworkRequest.js
@@ -1013,28 +1013,20 @@ return Common.ContentProvider.contentAsDataURL(content, this.mimeType, true, charset); } - _innerRequestContent() { + async _innerRequestContent() { if (this._contentRequested) return; this._contentRequested = true; - /** - * @param {?Protocol.Error} error - * @param {string} content - * @param {boolean} contentEncoded - * @this {SDK.NetworkRequest} - */ - function onResourceContent(error, content, contentEncoded) { - this._content = error ? null : content; - this._contentError = error; - this._contentEncoded = contentEncoded; - var callbacks = this._pendingContentCallbacks.slice(); - for (var i = 0; i < callbacks.length; ++i) - callbacks[i](this._content); - this._pendingContentCallbacks.length = 0; - delete this._contentRequested; - } - this._networkManager.target().networkAgent().getResponseBody(this._requestId, onResourceContent.bind(this)); + var response = + await this._networkManager.target().networkAgent().invoke_getResponseBody({requestId: this._requestId}); + + this._content = response[Protocol.Error] ? null : response.body; + this._contentError = response[Protocol.Error]; + this._contentEncoded = response.base64Encoded; + for (var callback of this._pendingContentCallbacks.splice(0)) + callback(this._content); + delete this._contentRequested; } /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/module.json b/third_party/WebKit/Source/devtools/front_end/sdk/module.json index 1965218..f6eec53b 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/module.json +++ b/third_party/WebKit/Source/devtools/front_end/sdk/module.json
@@ -106,34 +106,104 @@ }, { "type": "setting", + "category": "Rendering", "settingName": "showPaintRects", "settingType": "boolean", "storageType": "session", + "options": [ + { + "value": true, + "title": "Show paint flashing rectangles" + }, + { + "value": false, + "title": "Hide paint flashing rectangles" + } + ], "defaultValue": false }, { "type": "setting", + "category": "Rendering", "settingName": "showDebugBorders", "settingType": "boolean", "storageType": "session", + "options": [ + { + "value": true, + "title": "Show layer borders" + }, + { + "value": false, + "title": "Hide layer borders" + } + ], "defaultValue": false }, { "type": "setting", + "category": "Rendering", "settingName": "showFPSCounter", "settingType": "boolean", "storageType": "session", + "options": [ + { + "value": true, + "title": "Show frames per second (FPS) meter" + }, + { + "value": false, + "title": "Hide frames per second (FPS) meter" + } + ], "defaultValue": false }, { "type": "setting", + "category": "Rendering", "settingName": "showScrollBottleneckRects", "settingType": "boolean", "storageType": "session", + "options": [ + { + "value": true, + "title": "Show scroll performance bottlenecks" + }, + { + "value": false, + "title": "Hide scroll performance bottlenecks" + } + ], "defaultValue": false }, { "type": "setting", + "category": "Rendering", + "settingName": "emulatedCSSMedia", + "settingType": "enum", + "storageType": "session", + "defaultValue": "", + "options": [ + { + "title": "Do not emulate CSS media type", + "text": "No emulation", + "value": "" + }, + { + "title": "Emulate CSS print media type", + "text": "print", + "value": "print" + }, + { + "title": "Emulate CSS screen media type", + "text": "screen", + "value": "screen" + } + ], + "tags": "query" + }, + { + "type": "setting", "category": "Console", "title": "Enable custom formatters", "settingName": "customFormatters",
diff --git a/third_party/WebKit/Source/devtools/front_end/security/SecurityPanel.js b/third_party/WebKit/Source/devtools/front_end/security/SecurityPanel.js index 4db6bdc..1025b2a 100644 --- a/third_party/WebKit/Source/devtools/front_end/security/SecurityPanel.js +++ b/third_party/WebKit/Source/devtools/front_end/security/SecurityPanel.js
@@ -63,12 +63,9 @@ * @param {!Event} e */ function showCertificateViewer(e) { - function certificateCallback(names) { - InspectorFrontendHost.showCertificateViewer(names); - } - e.consume(); - SDK.multitargetNetworkManager.getCertificate(origin, certificateCallback); + SDK.multitargetNetworkManager.getCertificate(origin).then( + names => InspectorFrontendHost.showCertificateViewer(names)); } return UI.createTextButton(text, showCertificateViewer, 'security-certificate-button');
diff --git a/third_party/WebKit/Source/devtools/front_end/settings/SettingsScreen.js b/third_party/WebKit/Source/devtools/front_end/settings/SettingsScreen.js index 098edceb..75c9e9a0 100644 --- a/third_party/WebKit/Source/devtools/front_end/settings/SettingsScreen.js +++ b/third_party/WebKit/Source/devtools/front_end/settings/SettingsScreen.js
@@ -146,8 +146,6 @@ ['', 'Appearance', 'Elements', 'Sources', 'Network', 'Profiler', 'Console', 'Extensions']; /** @type {!Map<string, !Element>} */ this._nameToSection = new Map(); - /** @type {!Map<string, !Element>} */ - this._nameToSettingElement = new Map(); for (var sectionName of explicitSectionOrder) this._sectionElement(sectionName); self.runtime.extensions('setting').forEach(this._addSetting.bind(this)); @@ -181,33 +179,11 @@ _addSetting(extension) { if (!Settings.GenericSettingsTab.isSettingVisible(extension)) return; - var descriptor = extension.descriptor(); - var sectionName = descriptor['category']; - var settingName = descriptor['settingName']; - var setting = Common.moduleSetting(settingName); - var uiTitle = Common.UIString(extension.title()); - - var sectionElement = this._sectionElement(sectionName); - var settingControl; - - switch (descriptor['settingType']) { - case 'boolean': - settingControl = UI.SettingsUI.createSettingCheckbox(uiTitle, setting); - break; - case 'enum': - if (Array.isArray(descriptor['options'])) - settingControl = UI.SettingsUI.createSettingSelect(uiTitle, descriptor['options'], setting); - else - console.error('Enum setting defined without options'); - break; - default: - console.error('Invalid setting type: ' + descriptor['settingType']); - return; - } - if (settingControl) { - this._nameToSettingElement.set(settingName, settingControl); + var sectionElement = this._sectionElement(extension.descriptor()['category']); + var setting = Common.moduleSetting(extension.descriptor()['settingName']); + var settingControl = UI.SettingsUI.createControlForSetting(setting); + if (settingControl) sectionElement.appendChild(settingControl); - } } /**
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/PerformanceModel.js b/third_party/WebKit/Source/devtools/front_end/timeline/PerformanceModel.js index c1471f7..90bffef 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/PerformanceModel.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/PerformanceModel.js
@@ -39,6 +39,13 @@ } /** + * @return {number|undefined} + */ + recordStartTime() { + return this._recordStartTime; + } + + /** * @param {!SDK.TracingModel} model */ setTracingModel(model) {
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineHistoryManager.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineHistoryManager.js new file mode 100644 index 0000000..68ffb79 --- /dev/null +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineHistoryManager.js
@@ -0,0 +1,421 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +Timeline.TimelineHistoryManager = class { + constructor() { + /** @type {!Array<!Timeline.PerformanceModel>} */ + this._recordings = []; + this._action = UI.actionRegistry.action('timeline.show-history'); + this._action.setEnabled(false); + /** @type {!Map<string, number>} */ + this._nextNumberByDomain = new Map(); + this._button = new Timeline.TimelineHistoryManager.ToolbarButton(this._action); + + this._allOverviews = [ + {constructor: Timeline.TimelineEventOverviewResponsiveness, height: 3}, + {constructor: Timeline.TimelineEventOverviewFrames, height: 16}, + {constructor: Timeline.TimelineEventOverviewCPUActivity, height: 20}, + {constructor: Timeline.TimelineEventOverviewNetwork, height: 8} + ]; + this._totalHeight = this._allOverviews.reduce((acc, entry) => acc + entry.height, 0); + this._enabled = true; + /** @type {?Timeline.PerformanceModel} */ + this._lastActiveModel = null; + } + + /** + * @param {!Timeline.PerformanceModel} performanceModel + */ + addRecording(performanceModel) { + this._lastActiveModel = performanceModel; + this._recordings.unshift(performanceModel); + this._buildPreview(performanceModel); + this._button.setText(this._title(performanceModel)); + this._updateState(); + if (this._recordings.length <= Timeline.TimelineHistoryManager._maxRecordings) + return; + var lruModel = this._recordings.reduce((a, b) => lastUsedTime(a) < lastUsedTime(b) ? a : b); + this._recordings.splice(this._recordings.indexOf(lruModel), 1); + lruModel.dispose(); + + /** + * @param {!Timeline.PerformanceModel} model + * @return {number} + */ + function lastUsedTime(model) { + return Timeline.TimelineHistoryManager._dataForModel(model).lastUsed; + } + } + + /** + * @param {boolean} enabled + */ + setEnabled(enabled) { + this._enabled = enabled; + this._updateState(); + } + + button() { + return this._button; + } + + clear() { + this._recordings.forEach(model => model.dispose()); + this._recordings = []; + this._lastActiveModel = null; + this._updateState(); + this._nextNumberByDomain.clear(); + } + + /** + * @return {!Promise<?Timeline.PerformanceModel>} + */ + async showHistoryDropDown() { + if (this._recordings.length < 2 || !this._enabled) + return null; + + var model = await Timeline.TimelineHistoryManager.DropDown.show( + this._recordings, /** @type {!Timeline.PerformanceModel} */ (this._lastActiveModel), this._button.element); + if (!model) + return null; + var index = this._recordings.indexOf(model); + if (index < 0) { + console.assert(false, `selected recording not found`); + return null; + } + Timeline.TimelineHistoryManager._dataForModel(model).lastUsed = Date.now(); + this._lastActiveModel = model; + this._button.setText(this._title(model)); + return model; + } + + cancelIfShowing() { + Timeline.TimelineHistoryManager.DropDown.cancelIfShowing(); + } + + _updateState() { + this._action.setEnabled(this._recordings.length > 1 && this._enabled); + } + + /** + * @param {!Timeline.PerformanceModel} performanceModel + * @return {!Element} + */ + static _previewElement(performanceModel) { + var data = Timeline.TimelineHistoryManager._dataForModel(performanceModel); + var startedAt = performanceModel.recordStartTime(); + data.time.textContent = + startedAt ? Common.UIString('(%s ago)', Timeline.TimelineHistoryManager._coarseAge(startedAt)) : ''; + return data.preview; + } + + /** + * @param {number} time + * @return {string} + */ + static _coarseAge(time) { + var seconds = Math.round((Date.now() - time) / 1000); + if (seconds < 50) + return Common.UIString('moments'); + var minutes = Math.round(seconds / 60); + if (minutes < 50) + return Common.UIString('%s m', minutes); + var hours = Math.round(minutes / 60); + return Common.UIString('%s h', hours); + } + + /** + * @param {!Timeline.PerformanceModel} performanceModel + * @return {string} + */ + _title(performanceModel) { + return Timeline.TimelineHistoryManager._dataForModel(performanceModel).title; + } + + /** + * @param {!Timeline.PerformanceModel} performanceModel + */ + _buildPreview(performanceModel) { + var parsedURL = performanceModel.timelineModel().pageURL().asParsedURL(); + var domain = parsedURL ? parsedURL.host : ''; + var sequenceNumber = this._nextNumberByDomain.get(domain) || 1; + var title = Common.UIString('%s #%d', domain, sequenceNumber); + this._nextNumberByDomain.set(domain, sequenceNumber + 1); + var timeElement = createElement('span'); + + var preview = createElementWithClass('div', 'preview-item vbox'); + var data = {preview: preview, title: title, time: timeElement, lastUsed: Date.now()}; + performanceModel[Timeline.TimelineHistoryManager._previewDataSymbol] = data; + + preview.appendChild(this._buildTextDetails(performanceModel, title, timeElement)); + var screenshotAndOverview = preview.createChild('div', 'hbox'); + screenshotAndOverview.appendChild(this._buildScreenshotThumbnail(performanceModel)); + screenshotAndOverview.appendChild(this._buildOverview(performanceModel)); + return data.preview; + } + + /** + * @param {!Timeline.PerformanceModel} performanceModel + * @param {string} title + * @param {!Element} timeElement + * @return {!Element} + */ + _buildTextDetails(performanceModel, title, timeElement) { + var container = createElementWithClass('div', 'text-details hbox'); + container.createChild('span', 'name').textContent = title; + var tracingModel = performanceModel.tracingModel(); + var duration = Number.millisToString(tracingModel.maximumRecordTime() - tracingModel.minimumRecordTime(), false); + var timeContainer = container.createChild('span', 'time'); + timeContainer.appendChild(createTextNode(duration)); + timeContainer.appendChild(timeElement); + return container; + } + + /** + * @param {!Timeline.PerformanceModel} performanceModel + * @return {!Element} + */ + _buildScreenshotThumbnail(performanceModel) { + var container = createElementWithClass('div', 'screenshot-thumb'); + var thumbnailAspectRatio = 3 / 2; + container.style.width = this._totalHeight * thumbnailAspectRatio + 'px'; + container.style.height = this._totalHeight + 'px'; + var filmStripModel = performanceModel.filmStripModel(); + var lastFrame = filmStripModel.frames().peekLast(); + if (!lastFrame) + return container; + lastFrame.imageDataPromise() + .then(data => UI.loadImageFromData(data)) + .then(image => image && container.appendChild(image)); + return container; + } + + /** + * @param {!Timeline.PerformanceModel} performanceModel + * @return {!Element} + */ + _buildOverview(performanceModel) { + var container = createElement('div'); + + container.style.width = Timeline.TimelineHistoryManager._previewWidth + 'px'; + container.style.height = this._totalHeight + 'px'; + var canvas = container.createChild('canvas'); + canvas.width = window.devicePixelRatio * Timeline.TimelineHistoryManager._previewWidth; + canvas.height = window.devicePixelRatio * this._totalHeight; + + var ctx = canvas.getContext('2d'); + var yOffset = 0; + for (var overview of this._allOverviews) { + var timelineOverview = new overview.constructor(); + timelineOverview.setCanvasSize(Timeline.TimelineHistoryManager._previewWidth, overview.height); + timelineOverview.setModel(performanceModel); + timelineOverview.update(); + var sourceContext = timelineOverview.context(); + var imageData = sourceContext.getImageData(0, 0, sourceContext.canvas.width, sourceContext.canvas.height); + ctx.putImageData(imageData, 0, yOffset); + yOffset += overview.height; + } + return container; + } + + /** + * @param {!Timeline.PerformanceModel} model + * @return {?Timeline.TimelineHistoryManager.PreviewData} + */ + static _dataForModel(model) { + return model[Timeline.TimelineHistoryManager._previewDataSymbol] || null; + } +}; + +/** @typedef {!{preview: !Element, time: !Element, lastUsed: number, title: string}} */ +Timeline.TimelineHistoryManager.PreviewData; + +Timeline.TimelineHistoryManager._maxRecordings = 5; +Timeline.TimelineHistoryManager._previewWidth = 450; +Timeline.TimelineHistoryManager._previewDataSymbol = Symbol('previewData'); + +/** + * @implements {UI.ListDelegate<!Timeline.PerformanceModel>} + */ +Timeline.TimelineHistoryManager.DropDown = class { + /** + * @param {!Array<!Timeline.PerformanceModel>} models + */ + constructor(models) { + this._glassPane = new UI.GlassPane(); + this._glassPane.setSizeBehavior(UI.GlassPane.SizeBehavior.MeasureContent); + this._glassPane.setOutsideClickCallback(() => this._close(null)); + this._glassPane.setPointerEventsBehavior(UI.GlassPane.PointerEventsBehavior.BlockedByGlassPane); + this._glassPane.setAnchorBehavior(UI.GlassPane.AnchorBehavior.PreferBottom); + + var shadowRoot = + UI.createShadowRootWithCoreStyles(this._glassPane.contentElement, 'timeline/timelineHistoryManager.css'); + var contentElement = shadowRoot.createChild('div', 'drop-down'); + + this._listControl = new UI.ListControl(this, UI.ListMode.NonViewport); + this._listControl.element.addEventListener('mousemove', this._onMouseMove.bind(this), false); + this._listControl.replaceAllItems(models); + + contentElement.appendChild(this._listControl.element); + contentElement.addEventListener('keydown', this._onKeyDown.bind(this), false); + contentElement.addEventListener('click', this._onClick.bind(this), false); + + /** @type {?function(?Timeline.PerformanceModel)} */ + this._selectionDone = null; + } + + /** + * @param {!Array<!Timeline.PerformanceModel>} models + * @param {!Timeline.PerformanceModel} currentModel + * @param {!Element} anchor + * @return {!Promise<?Timeline.PerformanceModel>} + */ + static show(models, currentModel, anchor) { + if (Timeline.TimelineHistoryManager.DropDown._instance) + return Promise.resolve(/** @type {?Timeline.PerformanceModel} */ (null)); + var instance = new Timeline.TimelineHistoryManager.DropDown(models); + return instance._show(anchor, currentModel); + } + + static cancelIfShowing() { + if (!Timeline.TimelineHistoryManager.DropDown._instance) + return; + Timeline.TimelineHistoryManager.DropDown._instance._close(null); + } + + /** + * @param {!Element} anchor + * @param {!Timeline.PerformanceModel} currentModel + * @return {!Promise<?Timeline.PerformanceModel>} + */ + _show(anchor, currentModel) { + Timeline.TimelineHistoryManager.DropDown._instance = this; + this._glassPane.setContentAnchorBox(anchor.boxInWindow()); + this._glassPane.show(/** @type {!Document} */ (this._glassPane.contentElement.ownerDocument)); + this._listControl.element.focus(); + this._listControl.selectItem(currentModel); + + return new Promise(fulfill => this._selectionDone = fulfill); + } + + /** + * @param {!Event} event + */ + _onMouseMove(event) { + var node = event.target.enclosingNodeOrSelfWithClass('preview-item'); + var listItem = node && this._listControl.itemForNode(node); + if (!listItem) + return; + this._listControl.selectItem(listItem); + } + + /** + * @param {!Event} event + */ + _onClick(event) { + if (!event.target.enclosingNodeOrSelfWithClass('preview-item')) + return; + this._close(this._listControl.selectedItem()); + } + + /** + * @param {!Event} event + */ + _onKeyDown(event) { + switch (event.key) { + case 'Escape': + this._close(null); + break; + case 'Enter': + this._close(this._listControl.selectedItem()); + break; + default: + return; + } + event.consume(true); + } + + /** + * @param {?Timeline.PerformanceModel} model + */ + _close(model) { + this._selectionDone(model); + this._glassPane.hide(); + Timeline.TimelineHistoryManager.DropDown._instance = null; + } + + /** + * @override + * @param {!Timeline.PerformanceModel} item + * @return {!Element} + */ + createElementForItem(item) { + var element = Timeline.TimelineHistoryManager._previewElement(item); + element.classList.remove('selected'); + return element; + } + + /** + * @override + * @param {!Timeline.PerformanceModel} item + * @return {number} + */ + heightForItem(item) { + console.assert(false, 'Should not be called'); + return 0; + } + + /** + * @override + * @param {!Timeline.PerformanceModel} item + * @return {boolean} + */ + isItemSelectable(item) { + return true; + } + + /** + * @override + * @param {?Timeline.PerformanceModel} from + * @param {?Timeline.PerformanceModel} to + * @param {?Element} fromElement + * @param {?Element} toElement + */ + selectedItemChanged(from, to, fromElement, toElement) { + if (fromElement) + fromElement.classList.remove('selected'); + if (toElement) + toElement.classList.add('selected'); + } +}; + +/** + * @type {?Timeline.TimelineHistoryManager.DropDown} + */ +Timeline.TimelineHistoryManager.DropDown._instance = null; + + +Timeline.TimelineHistoryManager.ToolbarButton = class extends UI.ToolbarItem { + /** + * @param {!UI.Action} action + */ + constructor(action) { + super(createElementWithClass('button', 'dropdown-button')); + var shadowRoot = UI.createShadowRootWithCoreStyles(this.element, 'timeline/historyToolbarButton.css'); + + this._contentElement = shadowRoot.createChild('span', 'content'); + var dropdownArrowIcon = UI.Icon.create('smallicon-triangle-down'); + shadowRoot.appendChild(dropdownArrowIcon); + this.element.addEventListener('click', () => void action.execute(), false); + this.setEnabled(action.enabled()); + action.addEventListener(UI.Action.Events.Enabled, data => this.setEnabled(/** @type {boolean} */ (data))); + } + + /** + * @param {string} text + */ + setText(text) { + this._contentElement.textContent = text; + } +};
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js index ab801d7..faa7317b 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
@@ -52,6 +52,10 @@ this._millisecondsToRecordAfterLoadEvent = 3000; this._toggleRecordAction = /** @type {!UI.Action }*/ (UI.actionRegistry.action('timeline.toggle-recording')); + this._recordReloadAction = + /** @type {!UI.Action }*/ (UI.actionRegistry.action('timeline.record-reload')); + this._historyManager = + Runtime.experiments.isEnabled('timelineKeepHistory') ? new Timeline.TimelineHistoryManager() : null; /** @type {!Array<!TimelineModel.TimelineModelFilter>} */ this._filters = []; @@ -158,6 +162,8 @@ */ willHide() { UI.context.setFlavor(Timeline.TimelinePanel, null); + if (this._historyManager) + this._historyManager.cancelIfShowing(); } /** @@ -216,10 +222,15 @@ _populateToolbar() { // Record this._panelToolbar.appendToolbarItem(UI.Toolbar.createActionButton(this._toggleRecordAction)); - this._panelToolbar.appendToolbarItem(UI.Toolbar.createActionButtonForId('timeline.record-reload')); + this._panelToolbar.appendToolbarItem(UI.Toolbar.createActionButton(this._recordReloadAction)); this._clearButton = new UI.ToolbarButton(Common.UIString('Clear'), 'largeicon-clear'); - this._clearButton.addEventListener(UI.ToolbarButton.Events.Click, () => this._clear()); + this._clearButton.addEventListener(UI.ToolbarButton.Events.Click, () => this._onClearButton()); this._panelToolbar.appendToolbarItem(this._clearButton); + // History + if (this._historyManager) { + this._panelToolbar.appendSeparator(); + this._panelToolbar.appendToolbarItem(this._historyManager.button()); + } this._panelToolbar.appendSeparator(); // View @@ -366,6 +377,12 @@ return true; } + async _showHistory() { + var model = await this._historyManager.showHistoryDropDown(); + if (model && model !== this._performanceModel) + this._setModel(model); + } + /** * @return {boolean} */ @@ -553,6 +570,9 @@ var state = Timeline.TimelinePanel.State; this._toggleRecordAction.setToggled(this._state === state.Recording); this._toggleRecordAction.setEnabled(this._state === state.Recording || this._state === state.Idle); + this._recordReloadAction.setEnabled(this._state === state.Idle); + if (this._historyManager) + this._historyManager.setEnabled(this._state === state.Idle); this._clearButton.setEnabled(this._state === state.Idle); this._panelToolbar.setEnabled(this._state !== state.Loading); this._dropTarget.setEnabled(this._state === state.Idle); @@ -574,6 +594,12 @@ this._startRecording(); } + _onClearButton() { + if (this._historyManager) + this._historyManager.clear(); + this._clear(); + } + _clear() { this._showLandingPage(); this._reset(); @@ -589,7 +615,7 @@ * @param {?Timeline.PerformanceModel} model */ _setModel(model) { - if (this._performanceModel) + if (this._performanceModel && !this._historyManager) this._performanceModel.dispose(); this._performanceModel = model; this._currentView.setModel(model); @@ -611,7 +637,6 @@ } else { this.requestWindowTimes(0, Infinity); } - this._overviewPane.scheduleUpdate(); this.select(null); if (this._flameChart) @@ -769,6 +794,8 @@ performanceModel.setTracingModel(tracingModel); this._backingStorage = backingStorage; this._setModel(performanceModel); + if (this._historyManager) + this._historyManager.addRecording(performanceModel); } _showRecordingStarted() { @@ -1304,6 +1331,9 @@ case 'timeline.jump-to-next-frame': panel._jumpToFrame(1); return true; + case 'timeline.show-history': + panel._showHistory(); + return true; } return false; }
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/historyToolbarButton.css b/third_party/WebKit/Source/devtools/front_end/timeline/historyToolbarButton.css new file mode 100644 index 0000000..f66188b --- /dev/null +++ b/third_party/WebKit/Source/devtools/front_end/timeline/historyToolbarButton.css
@@ -0,0 +1,24 @@ +/* + * Copyright 2017 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +:host { + width: 160px; + height: 26px; + text-align: left; + display: flex; +} + +:host([disabled]) { + opacity: .5; +} + +.content { + padding-right: 5px; + overflow: hidden; + text-overflow: ellipsis; + flex: 1 1; + min-width: 35px; +}
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/module.json b/third_party/WebKit/Source/devtools/front_end/timeline/module.json index b65c7ba6..eabd0a9 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/module.json +++ b/third_party/WebKit/Source/devtools/front_end/timeline/module.json
@@ -149,6 +149,27 @@ "shortcut": "]" } ] + }, + { + "type": "@UI.ActionDelegate", + "actionId": "timeline.show-history", + "className": "Timeline.TimelinePanel.ActionDelegate", + "category": "Performance", + "title": "Show recent timeline sessions", + "experiment": "timelineKeepHistory", + "contextTypes": [ + "Timeline.TimelinePanel" + ], + "bindings": [ + { + "platform": "windows,linux", + "shortcut": "Ctrl+H" + }, + { + "platform": "mac", + "shortcut": "Meta+Y" + } + ] } ], "dependencies": [ @@ -173,6 +194,7 @@ "TimelineFlameChartDataProvider.js", "TimelineFlameChartNetworkDataProvider.js", "TimelineFlameChartView.js", + "TimelineHistoryManager.js", "TimelineTreeModeView.js", "TimelineTreeView.js", "EventsTimelineTreeView.js", @@ -182,8 +204,10 @@ "TimelinePanel.js" ], "resources": [ + "historyToolbarButton.css", "invalidationsTree.css", "timelineFlamechartPopover.css", + "timelineHistoryManager.css", "timelinePanel.css", "timelinePaintProfiler.css", "timelineStatusDialog.css"
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/timelineHistoryManager.css b/third_party/WebKit/Source/devtools/front_end/timeline/timelineHistoryManager.css new file mode 100644 index 0000000..b9b69b63 --- /dev/null +++ b/third_party/WebKit/Source/devtools/front_end/timeline/timelineHistoryManager.css
@@ -0,0 +1,56 @@ +/* + * Copyright 2017 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +.drop-down { + padding: 1px; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2), 0 2px 4px rgba(0, 0, 0, 0.2), 0 2px 6px rgba(0, 0, 0, 0.1); + background: white; +} + +.preview-item { + border-color: transparent; + border-style: solid; + border-width: 1px 5px; + padding: 2px 0px; + margin: 2px 1px; +} + +.preview-item.selected { + border-color: rgb(56, 121, 217); +} + +.text-details { + font-size: 11px; + padding: 3px; +} + +.text-details span { + flex: 1 0; + padding-left: 8px; + padding-right: 8px; +} + +.text-details .name { + font-weight: bold; +} + +.text-details span.time { + color: #555; + text-align: right; +} + +.screenshot-thumb { + display: flex; + border: 1px solid #ccc; + margin: 2px 4px; +} + +.screenshot-thumb img { + margin: auto; + flex: 1 1; + max-width: 100%; + max-height: 100%; +}
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineModel.js b/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineModel.js index bcdfdf2c..b5e3377 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineModel.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineModel.js
@@ -33,7 +33,7 @@ */ TimelineModel.TimelineModel = class { constructor() { - this.reset(); + this._reset(); } /** @@ -168,7 +168,7 @@ * @param {boolean=} produceTraceStartedInPage */ setEvents(tracingModel, produceTraceStartedInPage) { - this.reset(); + this._reset(); this._resetProcessingState(); this._minimumRecordTime = tracingModel.minimumRecordTime(); @@ -225,6 +225,9 @@ pageDevToolsMetadataEvents.push(event); var frames = ((event.args['data'] && event.args['data']['frames']) || []); frames.forEach(payload => this._addPageFrame(event, payload)); + var rootFrame = this.rootFrames()[0]; + if (rootFrame && rootFrame.url) + this._pageURL = rootFrame.url; } else if (event.name === TimelineModel.TimelineModel.DevToolsMetadataEvent.TracingSessionIdForWorker) { workersDevToolsMetadataEvents.push(event); } else if (event.name === TimelineModel.TimelineModel.DevToolsMetadataEvent.TracingStartedInBrowser) { @@ -767,6 +770,8 @@ return false; if (!eventData['isMainFrame']) break; + if (eventData.url) + this._pageURL = eventData.url; this._hadCommitLoad = true; this._firstCompositeLayers = null; break; @@ -871,7 +876,7 @@ parent.addChild(pageFrame); } - reset() { + _reset() { this._virtualThreads = []; /** @type {!Array<!SDK.TracingModel.Event>} */ this._mainThreadEvents = []; @@ -897,6 +902,7 @@ this._pageFrames = new Map(); /** @type {!Map<string, !Array<!SDK.TracingModel.Event>>} */ this._eventsByFrame = new Map(); + this._pageURL = ''; this._minimumRecordTime = 0; this._maximumRecordTime = 0; @@ -980,6 +986,13 @@ } /** + * @return {string} + */ + pageURL() { + return this._pageURL; + } + + /** * @param {string} frameId * @return {?TimelineModel.TimelineModel.PageFrame} */
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/ListControl.js b/third_party/WebKit/Source/devtools/front_end/ui/ListControl.js index 9e3da79b..a2b92c00 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/ListControl.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/ListControl.js
@@ -70,6 +70,7 @@ this._itemToElement = new Map(); this._selectedIndex = -1; + this.element.tabIndex = -1; this.element.addEventListener('click', this._onClick.bind(this), false); this.element.addEventListener('keydown', this._onKeyDown.bind(this), false);
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/SettingsUI.js b/third_party/WebKit/Source/devtools/front_end/ui/SettingsUI.js index c16b5458..76b306fe 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/SettingsUI.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/SettingsUI.js
@@ -123,6 +123,29 @@ }; /** + * @param {!Common.Setting} setting + * @return {?Element} + */ +UI.SettingsUI.createControlForSetting = function(setting) { + if (!setting.extension()) + return null; + var descriptor = setting.extension().descriptor(); + var uiTitle = Common.UIString(setting.title() || ''); + switch (descriptor['settingType']) { + case 'boolean': + return UI.SettingsUI.createSettingCheckbox(uiTitle, setting); + case 'enum': + if (Array.isArray(descriptor['options'])) + return UI.SettingsUI.createSettingSelect(uiTitle, descriptor['options'], setting); + console.error('Enum setting defined without options'); + return null; + default: + console.error('Invalid setting type: ' + descriptor['settingType']); + return null; + } +}; + +/** * @interface */ UI.SettingUI = function() {};
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js b/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js index dea0e9b..909d19a 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
@@ -68,6 +68,7 @@ /** @type {?Element} */ var longClickGlyph = null; toggled(); + button.setEnabled(action.enabled()); return button; /**
diff --git a/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py b/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py index cd5a41732..308171f 100755 --- a/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py +++ b/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py
@@ -55,7 +55,6 @@ "DOMDebugger", "IndexedDB", "LayerTree", - "Network", ])
diff --git a/third_party/WebKit/Source/modules/accessibility/AXMenuList.h b/third_party/WebKit/Source/modules/accessibility/AXMenuList.h index 88d1d786..856dbd1 100644 --- a/third_party/WebKit/Source/modules/accessibility/AXMenuList.h +++ b/third_party/WebKit/Source/modules/accessibility/AXMenuList.h
@@ -49,6 +49,8 @@ void DidHidePopup(); private: + friend class AXMenuListOption; + AXMenuList(LayoutMenuList*, AXObjectCacheImpl&); bool IsMenuList() const override { return true; }
diff --git a/third_party/WebKit/Source/modules/accessibility/AXMenuListOption.cpp b/third_party/WebKit/Source/modules/accessibility/AXMenuListOption.cpp index af8b879f..f8c4eec 100644 --- a/third_party/WebKit/Source/modules/accessibility/AXMenuListOption.cpp +++ b/third_party/WebKit/Source/modules/accessibility/AXMenuListOption.cpp
@@ -28,6 +28,7 @@ #include "SkMatrix44.h" #include "core/dom/AccessibleNode.h" #include "core/html/HTMLSelectElement.h" +#include "modules/accessibility/AXMenuList.h" #include "modules/accessibility/AXMenuListPopup.h" #include "modules/accessibility/AXObjectCacheImpl.h" @@ -48,6 +49,12 @@ AXMockObject::Detach(); } +LocalFrameView* AXMenuListOption::DocumentFrameView() const { + if (IsDetached()) + return nullptr; + return element_->GetDocument().View(); +} + AccessibilityRole AXMenuListOption::RoleValue() const { const AtomicString& aria_role = GetAOMPropertyOrARIAAttribute(AOMStringProperty::kRole); @@ -72,14 +79,21 @@ if (!select) return nullptr; AXObjectImpl* select_ax_object = AxObjectCache().GetOrCreate(select); - if (select_ax_object->HasChildren()) { - const auto& child_objects = select_ax_object->Children(); - DCHECK(!child_objects.IsEmpty()); + + // This happens if the <select> is not rendered. Return it and move on. + if (!select_ax_object->IsMenuList()) + return select_ax_object; + + AXMenuList* menu_list = ToAXMenuList(select_ax_object); + if (menu_list->HasChildren()) { + const auto& child_objects = menu_list->Children(); + if (child_objects.IsEmpty()) + return nullptr; DCHECK_EQ(child_objects.size(), 1UL); DCHECK(child_objects[0]->IsMenuListPopup()); ToAXMenuListPopup(child_objects[0].Get())->UpdateChildrenIfNecessary(); } else { - select_ax_object->UpdateChildrenIfNecessary(); + menu_list->UpdateChildrenIfNecessary(); } return parent_.Get(); }
diff --git a/third_party/WebKit/Source/modules/accessibility/AXMenuListOption.h b/third_party/WebKit/Source/modules/accessibility/AXMenuListOption.h index ced0f73..32f42e9 100644 --- a/third_party/WebKit/Source/modules/accessibility/AXMenuListOption.h +++ b/third_party/WebKit/Source/modules/accessibility/AXMenuListOption.h
@@ -52,6 +52,7 @@ Node* GetNode() const override { return element_; } void Detach() override; bool IsDetached() const override { return !element_; } + LocalFrameView* DocumentFrameView() const override; AccessibilityRole RoleValue() const override; bool CanHaveChildren() const override { return false; } AXObjectImpl* ComputeParent() const override;
diff --git a/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp b/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp index 1d95bc7..85e95e73 100644 --- a/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp +++ b/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp
@@ -302,6 +302,14 @@ resource_request_->SetUseStreamOnResponse(use_stream_on_response); } +bool WebURLRequest::GetKeepalive() const { + return resource_request_->GetKeepalive(); +} + +void WebURLRequest::SetKeepalive(bool keepalive) { + resource_request_->SetKeepalive(keepalive); +} + WebURLRequest::ServiceWorkerMode WebURLRequest::GetServiceWorkerMode() const { return resource_request_->GetServiceWorkerMode(); }
diff --git a/third_party/WebKit/Source/platform/loader/fetch/RawResource.h b/third_party/WebKit/Source/platform/loader/fetch/RawResource.h index 31807a1..6c692aad 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/RawResource.h +++ b/third_party/WebKit/Source/platform/loader/fetch/RawResource.h
@@ -96,14 +96,14 @@ void ReportResourceTimingToClients(const ResourceTimingInfo&) override; }; -#if ENABLE(SECURITY_ASSERT) +// TODO(yhirano): Recover #if ENABLE(SECURITY_ASSERT) when we stop adding +// RawResources to MemoryCache. inline bool IsRawResource(const Resource& resource) { Resource::Type type = resource.GetType(); return type == Resource::kMainResource || type == Resource::kRaw || type == Resource::kTextTrack || type == Resource::kMedia || type == Resource::kManifest || type == Resource::kImportResource; } -#endif inline RawResource* ToRawResource(Resource* resource) { SECURITY_DCHECK(!resource || IsRawResource(*resource)); return static_cast<RawResource*>(resource);
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp index 5cedba9..c2b85c7 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp +++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp
@@ -35,6 +35,7 @@ #include "platform/loader/fetch/FetchContext.h" #include "platform/loader/fetch/FetchInitiatorTypeNames.h" #include "platform/loader/fetch/MemoryCache.h" +#include "platform/loader/fetch/RawResource.h" #include "platform/loader/fetch/ResourceLoader.h" #include "platform/loader/fetch/ResourceLoadingLog.h" #include "platform/loader/fetch/ResourceTimingInfo.h" @@ -152,6 +153,23 @@ return kResourceLoadPriorityUnresolved; } +bool ShouldResourceBeAddedToMemoryCache(const FetchParameters& params, + Resource* resource) { + if (!IsMainThread()) + return false; + if (params.Options().data_buffering_policy == kDoNotBufferData) + return false; + + // TODO(yhirano): Stop adding RawResources to MemoryCache completely. + if (resource->GetType() == Resource::kMainResource) + return false; + if (IsRawResource(*resource) && + (params.IsSpeculativePreload() || params.IsLinkPreload())) { + return false; + } + return true; +} + } // namespace ResourceLoadPriority ResourceFetcher::ComputeLoadPriority( @@ -440,8 +458,10 @@ resource->SetCacheIdentifier(cache_identifier); resource->Finish(); - if (!substitute_data.IsValid()) + if (ShouldResourceBeAddedToMemoryCache(params, resource) && + !substitute_data.IsValid()) { GetMemoryCache()->Add(resource); + } return resource; } @@ -795,12 +815,8 @@ } resource->SetCacheIdentifier(cache_identifier); - // - Don't add main resource to cache to prevent reuse. - // - Don't add the resource if its body will not be stored. - if (IsMainThread() && factory.GetType() != Resource::kMainResource && - params.Options().data_buffering_policy != kDoNotBufferData) { + if (ShouldResourceBeAddedToMemoryCache(params, resource)) GetMemoryCache()->Add(resource); - } return resource; }
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.cpp index d6a19cca..52c9e86 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.cpp +++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.cpp
@@ -57,6 +57,7 @@ has_user_gesture_(false), download_to_file_(false), use_stream_on_response_(false), + keepalive_(false), should_reset_app_cache_(false), service_worker_mode_(WebURLRequest::ServiceWorkerMode::kAll), priority_(kResourceLoadPriorityLowest), @@ -101,6 +102,7 @@ SetHasUserGesture(data->has_user_gesture_); SetDownloadToFile(data->download_to_file_); SetUseStreamOnResponse(data->use_stream_on_response_); + SetKeepalive(data->keepalive_); SetServiceWorkerMode(data->service_worker_mode_); SetShouldResetAppCache(data->should_reset_app_cache_); SetRequestorID(data->requestor_id_); @@ -150,6 +152,7 @@ data->has_user_gesture_ = has_user_gesture_; data->download_to_file_ = download_to_file_; data->use_stream_on_response_ = use_stream_on_response_; + data->keepalive_ = keepalive_; data->service_worker_mode_ = service_worker_mode_; data->should_reset_app_cache_ = should_reset_app_cache_; data->requestor_id_ = requestor_id_;
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.h b/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.h index 9964ecd..31ae7068 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.h +++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.h
@@ -217,6 +217,10 @@ use_stream_on_response_ = use_stream_on_response; } + // True if the request can work after the fetch group is terminated. + bool GetKeepalive() const { return keepalive_; } + void SetKeepalive(bool keepalive) { keepalive_ = keepalive; } + // The service worker mode indicating which service workers should get events // for this request. WebURLRequest::ServiceWorkerMode GetServiceWorkerMode() const { @@ -346,6 +350,7 @@ bool has_user_gesture_ : 1; bool download_to_file_ : 1; bool use_stream_on_response_ : 1; + bool keepalive_ : 1; bool should_reset_app_cache_ : 1; WebURLRequest::ServiceWorkerMode service_worker_mode_; ResourceLoadPriority priority_; @@ -401,6 +406,7 @@ bool download_to_file_; WebURLRequest::ServiceWorkerMode service_worker_mode_; bool use_stream_on_response_; + bool keepalive_; bool should_reset_app_cache_; ResourceLoadPriority priority_; int intra_priority_value_;
diff --git a/third_party/WebKit/Source/web/BUILD.gn b/third_party/WebKit/Source/web/BUILD.gn index c990fde..1d5f8ab 100644 --- a/third_party/WebKit/Source/web/BUILD.gn +++ b/third_party/WebKit/Source/web/BUILD.gn
@@ -55,8 +55,6 @@ "ContextMenuClientImpl.h", "DedicatedWorkerMessagingProxyProviderImpl.cpp", "DedicatedWorkerMessagingProxyProviderImpl.h", - "DevToolsEmulator.cpp", - "DevToolsEmulator.h", "EditorClientImpl.cpp", "EditorClientImpl.h", "ExternalDateTimeChooser.cpp",
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.cpp b/third_party/WebKit/Source/web/ChromeClientImpl.cpp index 51d3615..ea57c9a 100644 --- a/third_party/WebKit/Source/web/ChromeClientImpl.cpp +++ b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
@@ -53,6 +53,7 @@ #include "core/html/forms/DateTimeChooser.h" #include "core/html/forms/DateTimeChooserClient.h" #include "core/html/forms/DateTimeChooserImpl.h" +#include "core/inspector/DevToolsEmulator.h" #include "core/layout/HitTestResult.h" #include "core/layout/LayoutPart.h" #include "core/layout/compositing/CompositedSelection.h" @@ -116,7 +117,6 @@ #include "web/AudioOutputDeviceClientImpl.h" #include "web/ColorChooserPopupUIController.h" #include "web/ColorChooserUIController.h" -#include "web/DevToolsEmulator.h" #include "web/ExternalDateTimeChooser.h" #include "web/ExternalPopupMenu.h" #include "web/IndexedDBClientImpl.h"
diff --git a/third_party/WebKit/Source/web/InspectorEmulationAgent.cpp b/third_party/WebKit/Source/web/InspectorEmulationAgent.cpp index 5b2c2ec..fdb8515 100644 --- a/third_party/WebKit/Source/web/InspectorEmulationAgent.cpp +++ b/third_party/WebKit/Source/web/InspectorEmulationAgent.cpp
@@ -8,6 +8,7 @@ #include "core/frame/LocalFrameView.h" #include "core/frame/Settings.h" #include "core/frame/WebLocalFrameBase.h" +#include "core/inspector/DevToolsEmulator.h" #include "core/inspector/protocol/DOM.h" #include "core/page/Page.h" #include "platform/geometry/DoubleRect.h" @@ -16,7 +17,6 @@ #include "public/platform/Platform.h" #include "public/platform/WebFloatPoint.h" #include "public/platform/WebThread.h" -#include "web/DevToolsEmulator.h" namespace blink {
diff --git a/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp b/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp index 00c25a06..56b9734 100644 --- a/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp +++ b/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp
@@ -51,6 +51,7 @@ #include "core/html/HTMLMediaElement.h" #include "core/html/HTMLPlugInElement.h" #include "core/input/EventHandler.h" +#include "core/inspector/DevToolsEmulator.h" #include "core/layout/HitTestResult.h" #include "core/loader/DocumentLoader.h" #include "core/loader/FrameLoadRequest.h" @@ -105,7 +106,6 @@ #include "public/web/WebPluginParams.h" #include "public/web/WebViewClient.h" #include "v8/include/v8.h" -#include "web/DevToolsEmulator.h" #include "web/WebDevToolsAgentImpl.h" #include "web/WebDevToolsFrontendImpl.h" #include "web/WebPluginContainerImpl.h"
diff --git a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp index 6118ed2f..32b956d 100644 --- a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp +++ b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp
@@ -42,6 +42,7 @@ #include "core/frame/LocalFrameView.h" #include "core/frame/Settings.h" #include "core/frame/WebLocalFrameBase.h" +#include "core/inspector/DevToolsEmulator.h" #include "core/inspector/InspectedFrames.h" #include "core/inspector/InspectorAnimationAgent.h" #include "core/inspector/InspectorApplicationCacheAgent.h" @@ -85,7 +86,6 @@ #include "public/platform/WebString.h" #include "public/web/WebDevToolsAgentClient.h" #include "public/web/WebSettings.h" -#include "web/DevToolsEmulator.h" #include "web/InspectorEmulationAgent.h" #include "web/InspectorOverlayAgent.h" #include "web/WebFrameWidgetImpl.h"
diff --git a/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp b/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp index 76d4b0b..a246c8c2 100644 --- a/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp +++ b/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp
@@ -766,8 +766,8 @@ // Remote viewports are only applicable to local frames with remote ancestors. DCHECK(local_root_->Parent() && local_root_->Parent()->IsWebRemoteFrame()); - if (local_root_->GetFrameView()) { - local_root_->GetFrameView()->SetViewportIntersectionFromParent( + if (local_root_->GetFrame()) { + local_root_->GetFrame()->SetViewportIntersectionFromParent( viewport_intersection); } }
diff --git a/third_party/WebKit/Source/web/WebSettingsImpl.cpp b/third_party/WebKit/Source/web/WebSettingsImpl.cpp index 134d15f6d..61794c9 100644 --- a/third_party/WebKit/Source/web/WebSettingsImpl.cpp +++ b/third_party/WebKit/Source/web/WebSettingsImpl.cpp
@@ -33,9 +33,9 @@ #include "core/frame/Settings.h" #include "platform/graphics/DeferredImageDecoder.h" +#include "core/inspector/DevToolsEmulator.h" #include "public/platform/WebString.h" #include "public/platform/WebURL.h" -#include "web/DevToolsEmulator.h" #include "web/WebDevToolsAgentImpl.h" namespace blink {
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp index 9d68a677..9c3803e 100644 --- a/third_party/WebKit/Source/web/WebViewImpl.cpp +++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -73,6 +73,7 @@ #include "core/input/ContextMenuAllowedScope.h" #include "core/input/EventHandler.h" #include "core/input/TouchActionUtil.h" +#include "core/inspector/DevToolsEmulator.h" #include "core/layout/LayoutPart.h" #include "core/layout/TextAutosizer.h" #include "core/layout/api/LayoutViewItem.h" @@ -165,7 +166,6 @@ #include "web/AnimationWorkletProxyClientImpl.h" #include "web/CompositorWorkerProxyClientImpl.h" #include "web/DedicatedWorkerMessagingProxyProviderImpl.h" -#include "web/DevToolsEmulator.h" #include "web/FullscreenController.h" #include "web/LinkHighlightImpl.h" #include "web/PageOverlay.h"
diff --git a/third_party/WebKit/Source/web/tests/WebViewTest.cpp b/third_party/WebKit/Source/web/tests/WebViewTest.cpp index 7f4f3c7..1c33978 100644 --- a/third_party/WebKit/Source/web/tests/WebViewTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebViewTest.cpp
@@ -51,6 +51,7 @@ #include "core/html/HTMLIFrameElement.h" #include "core/html/HTMLInputElement.h" #include "core/html/HTMLTextAreaElement.h" +#include "core/inspector/DevToolsEmulator.h" #include "core/layout/api/LayoutViewItem.h" #include "core/loader/DocumentLoader.h" #include "core/loader/FrameLoadRequest.h" @@ -106,7 +107,6 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkCanvas.h" -#include "web/DevToolsEmulator.h" #include "web/WebSettingsImpl.h" #include "web/tests/FrameTestHelpers.h"
diff --git a/third_party/WebKit/public/platform/WebURLRequest.h b/third_party/WebKit/public/platform/WebURLRequest.h index ba9dcb8..99ba61d 100644 --- a/third_party/WebKit/public/platform/WebURLRequest.h +++ b/third_party/WebKit/public/platform/WebURLRequest.h
@@ -290,6 +290,10 @@ BLINK_PLATFORM_EXPORT bool UseStreamOnResponse() const; BLINK_PLATFORM_EXPORT void SetUseStreamOnResponse(bool); + // True if the request can work after the fetch group is terminated. + BLINK_PLATFORM_EXPORT bool GetKeepalive() const; + BLINK_PLATFORM_EXPORT void SetKeepalive(bool); + // The service worker mode indicating which service workers should get events // for this request. BLINK_PLATFORM_EXPORT ServiceWorkerMode GetServiceWorkerMode() const;
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 29d30f0..cb0382b 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -28729,6 +28729,11 @@ <int value="5" label="Shortcut. Restart required."/> </enum> +<enum name="PpdSource" type="int"> + <int value="0" label="PPD provided by user"/> + <int value="1" label="PPD downloaded from SCS"/> +</enum> + <enum name="PrecacheEvents" type="int"> <int value="0" label="PRECACHE_TASK_STARTED_PERIODIC"/> <int value="1" label="PRECACHE_TASK_STARTED_ONEOFF"/> @@ -29203,6 +29208,17 @@ <int value="4" label="Printer provider Web Store app launched"/> </enum> +<enum name="PrinterSetupResult" type="int"> + <int value="0" label="Fatal Error"/> + <int value="1" label="Success"/> + <int value="2" label="Printer Unreachable"/> + <int value="3" label="Could not contact debugd over dbus"/> + <int value="10" label="PPD exceeds size limit"/> + <int value="11" label="PPD Rejected by cupstestppd"/> + <int value="12" label="Could not find PPD"/> + <int value="13" label="Failed to download PPD"/> +</enum> + <enum name="PrintJobResult" type="int"> <int value="0" label="Unknown"/> <int value="1" label="Successful Finish"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index bff0523..56a5e0f 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -57161,6 +57161,15 @@ </summary> </histogram> +<histogram name="Printing.CUPS.PpdSource" enum="PpdSource"> + <owner>skau@chromium.org</owner> + <summary> + Records the source of PostScript Printer Description files used during + printer setup. Entries are recorded for every attempted configuration. Only + recorded on Chrome OS. + </summary> +</histogram> + <histogram name="Printing.CUPS.PrintersDiscovered" units="printers"> <owner>skau@chromium.org</owner> <summary> @@ -57169,6 +57178,15 @@ </summary> </histogram> +<histogram name="Printing.CUPS.PrinterSetupResult" enum="PrinterSetupResult"> + <owner>skau@chromium.org</owner> + <summary> + The success or error code for the setup of a CUPS printer. Recorded when + setup is attempted through the settings dialogs. Only recorded on Chrome + OS. + </summary> +</histogram> + <histogram name="Printing.CUPS.PrintJobsQueued" units="count"> <owner>skau@chromium.org</owner> <summary> @@ -91274,6 +91292,10 @@ <affected-histogram name="PageLoad.DocumentTiming.NavigationToLoadEventFired"/> <affected-histogram + name="PageLoad.Experimental.PaintTiming.NavigationToFirstMeaningfulPaint"/> + <affected-histogram + name="PageLoad.Experimental.PaintTiming.ParseStartToFirstMeaningfulPaint"/> + <affected-histogram name="PageLoad.PaintTiming.NavigationToFirstContentfulPaint"/> <affected-histogram name="PageLoad.PaintTiming.ParseStartToFirstContentfulPaint"/> @@ -91288,11 +91310,16 @@ <histogram_suffixes name="PageLoadMetricsClientsServiceWorkerSpecialApps" separator="."> <suffix name="inbox" label="Custom histogram for Inbox"/> + <suffix name="search" label="Custom histogram for Search"/> <affected-histogram name="PageLoad.Clients.ServiceWorker.DocumentTiming.NavigationToDOMContentLoadedEventFired"/> <affected-histogram name="PageLoad.Clients.ServiceWorker.DocumentTiming.NavigationToLoadEventFired"/> <affected-histogram + name="PageLoad.Clients.ServiceWorker.Experimental.PaintTiming.NavigationToFirstMeaningfulPaint"/> + <affected-histogram + name="PageLoad.Clients.ServiceWorker.Experimental.PaintTiming.ParseStartToFirstMeaningfulPaint"/> + <affected-histogram name="PageLoad.Clients.ServiceWorker.PaintTiming.NavigationToFirstContentfulPaint"/> <affected-histogram name="PageLoad.Clients.ServiceWorker.PaintTiming.ParseStartToFirstContentfulPaint"/>
diff --git a/tools/perf/benchmarks/system_health_smoke_test.py b/tools/perf/benchmarks/system_health_smoke_test.py index b7c9209..2918184 100644 --- a/tools/perf/benchmarks/system_health_smoke_test.py +++ b/tools/perf/benchmarks/system_health_smoke_test.py
@@ -98,7 +98,7 @@ self.skipTest('Benchmark %s is disabled' % SinglePageBenchmark.Name()) if self.id() in _DISABLED_TESTS: - self.skipTest('Test is explictly disabled') + self.skipTest('Test is explicitly disabled') self.assertEqual(0, SinglePageBenchmark().Run(options), msg='Failed: %s' % benchmark_class)
diff --git a/tools/win/DebugVisualizers/webkit.natvis b/tools/win/DebugVisualizers/webkit.natvis index 2d78312..8180fc7 100644 --- a/tools/win/DebugVisualizers/webkit.natvis +++ b/tools/win/DebugVisualizers/webkit.natvis
@@ -172,7 +172,7 @@ </Type> <!-- Layout: LayoutObject --> <Type Name="blink::LayoutObject"> - <DisplayString Condition="bitfields_.m_IsAnonymous">Anonymous</DisplayString> + <DisplayString Condition="bitfields_.is_anonymous_">Anonymous</DisplayString> <DisplayString>{node_}</DisplayString> </Type> <Type Name="blink::LayoutObjectChildList"> @@ -213,6 +213,17 @@ <Type Name="blink::NGBlockNode"> <DisplayString>{layout_box_}</DisplayString> </Type> + <Type Name="blink::NGInlineNode"> + <DisplayString>{*start_inline_}</DisplayString> + <Expand> + <Item Name="inline_node_data">*block_->ng_inline_node_data_</Item> + <Item Name="text_content">block_->ng_inline_node_data_->text_content_</Item> + <Item Name="items">block_->ng_inline_node_data_->items_</Item> + </Expand> + </Type> + <Type Name="blink::NGInlineItem"> + <DisplayString>{(NGInlineItem::NGInlineItemType)type_} {start_offset_}-{end_offset_} {*layout_object_}</DisplayString> + </Type> <Type Name="blink::NGFragment"> <DisplayString>{physical_fragment_}</DisplayString> </Type>
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc index 6dcdc91e..44af7cd 100644 --- a/ui/accessibility/platform/ax_platform_node_win.cc +++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -499,6 +499,18 @@ VARIANT var_id, VARIANT* role) { AXPlatformNodeWin* target; COM_OBJECT_VALIDATE_VAR_ID_1_ARG_AND_GET_TARGET(var_id, role, target); + + // For historical reasons, we return a string (typically + // containing the HTML tag name) as the MSAA role, rather + // than a int. + std::string role_string = target->StringOverrideForMSAARole(); + if (!role_string.empty()) { + role->vt = VT_BSTR; + std::wstring wsTmp(role_string.begin(), role_string.end()); + role->bstrVal = SysAllocString(wsTmp.c_str()); + return S_OK; + } + role->vt = VT_I4; role->lVal = target->MSAARole(); return S_OK; @@ -1029,77 +1041,379 @@ switch (GetData().role) { case ui::AX_ROLE_ALERT: return ROLE_SYSTEM_ALERT; + + case ui::AX_ROLE_ALERT_DIALOG: + return ROLE_SYSTEM_DIALOG; + + case ui::AX_ROLE_ANCHOR: + return ROLE_SYSTEM_LINK; + case ui::AX_ROLE_APPLICATION: return ROLE_SYSTEM_APPLICATION; - case ui::AX_ROLE_BUTTON_DROP_DOWN: - return ROLE_SYSTEM_BUTTONDROPDOWN; - case ui::AX_ROLE_POP_UP_BUTTON: - return ROLE_SYSTEM_BUTTONMENU; - case ui::AX_ROLE_CARET: - return ROLE_SYSTEM_CARET; - case ui::AX_ROLE_CHECK_BOX: - return ROLE_SYSTEM_CHECKBUTTON; - case ui::AX_ROLE_COMBO_BOX: - return ROLE_SYSTEM_COMBOBOX; - case ui::AX_ROLE_DIALOG: - return ROLE_SYSTEM_DIALOG; - case ui::AX_ROLE_GENERIC_CONTAINER: + + case ui::AX_ROLE_ARTICLE: + return ROLE_SYSTEM_DOCUMENT; + + case ui::AX_ROLE_AUDIO: return ROLE_SYSTEM_GROUPING; - case ui::AX_ROLE_GROUP: + + case ui::AX_ROLE_BANNER: return ROLE_SYSTEM_GROUPING; - case ui::AX_ROLE_IMAGE: - return ROLE_SYSTEM_GRAPHIC; - case ui::AX_ROLE_LINK: - return ROLE_SYSTEM_LINK; - case ui::AX_ROLE_LOCATION_BAR: - return ROLE_SYSTEM_GROUPING; - case ui::AX_ROLE_MENU_BAR: - return ROLE_SYSTEM_MENUBAR; - case ui::AX_ROLE_MENU_ITEM: - return ROLE_SYSTEM_MENUITEM; - case ui::AX_ROLE_MENU_LIST_POPUP: - return ROLE_SYSTEM_MENUPOPUP; - case ui::AX_ROLE_TREE: - return ROLE_SYSTEM_OUTLINE; - case ui::AX_ROLE_TREE_ITEM: - return ROLE_SYSTEM_OUTLINEITEM; - case ui::AX_ROLE_TAB: - return ROLE_SYSTEM_PAGETAB; - case ui::AX_ROLE_TAB_LIST: - return ROLE_SYSTEM_PAGETABLIST; - case ui::AX_ROLE_PANE: - return ROLE_SYSTEM_PANE; - case ui::AX_ROLE_PROGRESS_INDICATOR: - return ROLE_SYSTEM_PROGRESSBAR; + + case ui::AX_ROLE_BUSY_INDICATOR: + return ROLE_SYSTEM_ANIMATION; + case ui::AX_ROLE_BUTTON: return ROLE_SYSTEM_PUSHBUTTON; + + case ui::AX_ROLE_CANVAS: + return ROLE_SYSTEM_GRAPHIC; + + case ui::AX_ROLE_CAPTION: + return ROLE_SYSTEM_TEXT; + + case ui::AX_ROLE_CELL: + return ROLE_SYSTEM_CELL; + + case ui::AX_ROLE_CHECK_BOX: + return ROLE_SYSTEM_CHECKBUTTON; + + case ui::AX_ROLE_COLOR_WELL: + return ROLE_SYSTEM_TEXT; + + case ui::AX_ROLE_COLUMN: + return ROLE_SYSTEM_COLUMN; + + case ui::AX_ROLE_COLUMN_HEADER: + return ROLE_SYSTEM_COLUMNHEADER; + + case ui::AX_ROLE_COMBO_BOX: + return ROLE_SYSTEM_COMBOBOX; + + case ui::AX_ROLE_COMPLEMENTARY: + return ROLE_SYSTEM_GROUPING; + + case ui::AX_ROLE_CONTENT_INFO: + return ROLE_SYSTEM_TEXT; + + case ui::AX_ROLE_DATE: + case ui::AX_ROLE_DATE_TIME: + return ROLE_SYSTEM_DROPLIST; + + case ui::AX_ROLE_DESCRIPTION_LIST_DETAIL: + return ROLE_SYSTEM_TEXT; + + case ui::AX_ROLE_DESCRIPTION_LIST: + return ROLE_SYSTEM_LIST; + + case ui::AX_ROLE_DESCRIPTION_LIST_TERM: + return ROLE_SYSTEM_LISTITEM; + + case ui::AX_ROLE_DETAILS: + return ROLE_SYSTEM_GROUPING; + + case ui::AX_ROLE_DIALOG: + return ROLE_SYSTEM_DIALOG; + + case ui::AX_ROLE_DISCLOSURE_TRIANGLE: + return ROLE_SYSTEM_PUSHBUTTON; + + case ui::AX_ROLE_DOCUMENT: + case ui::AX_ROLE_ROOT_WEB_AREA: + case ui::AX_ROLE_WEB_AREA: + return ROLE_SYSTEM_DOCUMENT; + + case ui::AX_ROLE_EMBEDDED_OBJECT: + if (delegate_->GetChildCount()) { + return ROLE_SYSTEM_GROUPING; + } else { + return ROLE_SYSTEM_CLIENT; + } + + case ui::AX_ROLE_FIGURE: + return ROLE_SYSTEM_GROUPING; + + case ui::AX_ROLE_FEED: + return ROLE_SYSTEM_GROUPING; + + case ui::AX_ROLE_GENERIC_CONTAINER: + return ROLE_SYSTEM_GROUPING; + + case ui::AX_ROLE_GRID: + return ROLE_SYSTEM_TABLE; + + case ui::AX_ROLE_GROUP: + return ROLE_SYSTEM_GROUPING; + + case ui::AX_ROLE_HEADING: + return ROLE_SYSTEM_GROUPING; + + case ui::AX_ROLE_IFRAME: + return ROLE_SYSTEM_DOCUMENT; + + case ui::AX_ROLE_IFRAME_PRESENTATIONAL: + return ROLE_SYSTEM_GROUPING; + + case ui::AX_ROLE_IMAGE: + return ROLE_SYSTEM_GRAPHIC; + + case ui::AX_ROLE_IMAGE_MAP_LINK: + return ROLE_SYSTEM_LINK; + + case ui::AX_ROLE_INPUT_TIME: + return ROLE_SYSTEM_GROUPING; + + case ui::AX_ROLE_LABEL_TEXT: + case ui::AX_ROLE_LEGEND: + return ROLE_SYSTEM_TEXT; + + case ui::AX_ROLE_LINK: + return ROLE_SYSTEM_LINK; + + case ui::AX_ROLE_LIST: + return ROLE_SYSTEM_LIST; + + case ui::AX_ROLE_LIST_BOX: + return ROLE_SYSTEM_LIST; + + case ui::AX_ROLE_LIST_BOX_OPTION: + return ROLE_SYSTEM_LISTITEM; + + case ui::AX_ROLE_LIST_ITEM: + return ROLE_SYSTEM_LISTITEM; + + case ui::AX_ROLE_MAIN: + return ROLE_SYSTEM_GROUPING; + + case ui::AX_ROLE_MARK: + return ROLE_SYSTEM_TEXT; + + case ui::AX_ROLE_MARQUEE: + return ROLE_SYSTEM_ANIMATION; + + case ui::AX_ROLE_MATH: + return ROLE_SYSTEM_EQUATION; + + case ui::AX_ROLE_MENU: + case ui::AX_ROLE_MENU_BUTTON: + return ROLE_SYSTEM_MENUPOPUP; + + case ui::AX_ROLE_MENU_BAR: + return ROLE_SYSTEM_MENUBAR; + + case ui::AX_ROLE_MENU_ITEM: + return ROLE_SYSTEM_MENUITEM; + + case ui::AX_ROLE_MENU_ITEM_CHECK_BOX: + return ROLE_SYSTEM_MENUITEM; + + case ui::AX_ROLE_MENU_ITEM_RADIO: + return ROLE_SYSTEM_MENUITEM; + + case ui::AX_ROLE_MENU_LIST_POPUP: + return ROLE_SYSTEM_LIST; + + case ui::AX_ROLE_MENU_LIST_OPTION: + return ROLE_SYSTEM_LISTITEM; + + case ui::AX_ROLE_NAVIGATION: + return ROLE_SYSTEM_GROUPING; + + case ui::AX_ROLE_NOTE: + return ROLE_SYSTEM_GROUPING; + + case ui::AX_ROLE_OUTLINE: + return ROLE_SYSTEM_OUTLINE; + + case ui::AX_ROLE_POP_UP_BUTTON: { + std::string html_tag = GetData().GetStringAttribute(ui::AX_ATTR_HTML_TAG); + if (html_tag == "select") + return ROLE_SYSTEM_COMBOBOX; + return ROLE_SYSTEM_BUTTONMENU; + } + case ui::AX_ROLE_PRE: + return ROLE_SYSTEM_TEXT; + + case ui::AX_ROLE_PROGRESS_INDICATOR: + return ROLE_SYSTEM_PROGRESSBAR; + case ui::AX_ROLE_RADIO_BUTTON: return ROLE_SYSTEM_RADIOBUTTON; + + case ui::AX_ROLE_RADIO_GROUP: + return ROLE_SYSTEM_GROUPING; + + case ui::AX_ROLE_REGION: { + std::string html_tag = GetData().GetStringAttribute(ui::AX_ATTR_HTML_TAG); + if (html_tag == "section") + return ROLE_SYSTEM_GROUPING; + return ROLE_SYSTEM_PANE; + } + + case ui::AX_ROLE_ROW: { + // Role changes depending on whether row is inside a treegrid + // https://www.w3.org/TR/core-aam-1.1/#role-map-row + auto* container = FromNativeViewAccessible(GetParent()); + if (container && container->GetData().role == ui::AX_ROLE_GROUP) { + // If parent was a rowgroup, we need to look at the grandparent + container = FromNativeViewAccessible(container->GetParent()); + } + + if (!container) + return ROLE_SYSTEM_ROW; + + return ROLE_SYSTEM_OUTLINEITEM; + } + + case ui::AX_ROLE_ROW_HEADER: + return ROLE_SYSTEM_ROWHEADER; + + case ui::AX_ROLE_RUBY: + return ROLE_SYSTEM_TEXT; + + case ui::AX_ROLE_RULER: + return ROLE_SYSTEM_CLIENT; + + case ui::AX_ROLE_SCROLL_AREA: + return ROLE_SYSTEM_CLIENT; + case ui::AX_ROLE_SCROLL_BAR: return ROLE_SYSTEM_SCROLLBAR; - case ui::AX_ROLE_SPLITTER: - return ROLE_SYSTEM_SEPARATOR; + + case ui::AX_ROLE_SEARCH: + return ROLE_SYSTEM_GROUPING; + case ui::AX_ROLE_SLIDER: return ROLE_SYSTEM_SLIDER; + + case ui::AX_ROLE_SPIN_BUTTON: + return ROLE_SYSTEM_SPINBUTTON; + + case ui::AX_ROLE_SPIN_BUTTON_PART: + return ROLE_SYSTEM_PUSHBUTTON; + + case ui::AX_ROLE_ANNOTATION: + case ui::AX_ROLE_LIST_MARKER: case ui::AX_ROLE_STATIC_TEXT: return ROLE_SYSTEM_STATICTEXT; + + case ui::AX_ROLE_STATUS: + return ROLE_SYSTEM_STATUSBAR; + + case ui::AX_ROLE_SPLITTER: + return ROLE_SYSTEM_SEPARATOR; + + case ui::AX_ROLE_SVG_ROOT: + return ROLE_SYSTEM_GRAPHIC; + + case ui::AX_ROLE_TAB: + return ROLE_SYSTEM_PAGETAB; + + case ui::AX_ROLE_TABLE: + return ROLE_SYSTEM_TABLE; + + case ui::AX_ROLE_TABLE_HEADER_CONTAINER: + return ROLE_SYSTEM_GROUPING; + + case ui::AX_ROLE_TAB_LIST: + return ROLE_SYSTEM_PAGETABLIST; + + case ui::AX_ROLE_TAB_PANEL: + return ROLE_SYSTEM_PROPERTYPAGE; + + case ui::AX_ROLE_TERM: + return ROLE_SYSTEM_LISTITEM; + + case ui::AX_ROLE_TOGGLE_BUTTON: + return ROLE_SYSTEM_PUSHBUTTON; + case ui::AX_ROLE_TEXT_FIELD: + case ui::AX_ROLE_SEARCH_BOX: return ROLE_SYSTEM_TEXT; - case ui::AX_ROLE_TITLE_BAR: - return ROLE_SYSTEM_TITLEBAR; + + case ui::AX_ROLE_ABBR: + case ui::AX_ROLE_TIME: + return ROLE_SYSTEM_TEXT; + + case ui::AX_ROLE_TIMER: + return ROLE_SYSTEM_CLOCK; + case ui::AX_ROLE_TOOLBAR: return ROLE_SYSTEM_TOOLBAR; - case ui::AX_ROLE_WEB_VIEW: + + case ui::AX_ROLE_TOOLTIP: + return ROLE_SYSTEM_TOOLTIP; + + case ui::AX_ROLE_TREE: + return ROLE_SYSTEM_OUTLINE; + + case ui::AX_ROLE_TREE_GRID: + return ROLE_SYSTEM_OUTLINE; + + case ui::AX_ROLE_TREE_ITEM: + return ROLE_SYSTEM_OUTLINEITEM; + + case ui::AX_ROLE_LINE_BREAK: + return ROLE_SYSTEM_WHITESPACE; + + case ui::AX_ROLE_VIDEO: return ROLE_SYSTEM_GROUPING; + case ui::AX_ROLE_WINDOW: return ROLE_SYSTEM_WINDOW; - case ui::AX_ROLE_CLIENT: + + // TODO(dmazzoni): figure out the proper MSAA role for roles not called out + // here. default: - // This is the default role for MSAA. return ROLE_SYSTEM_CLIENT; } } +std::string AXPlatformNodeWin::StringOverrideForMSAARole() { + std::string html_tag = GetData().GetStringAttribute(ui::AX_ATTR_HTML_TAG); + + switch (GetData().role) { + case ui::AX_ROLE_BLOCKQUOTE: + case ui::AX_ROLE_DEFINITION: + case ui::AX_ROLE_IMAGE_MAP: + return html_tag; + + case ui::AX_ROLE_CANVAS: + if (GetData().GetBoolAttribute(ui::AX_ATTR_CANVAS_HAS_FALLBACK)) { + // TODO(dougt) why not just use the html_tag? + return "canvas"; + } + break; + + case ui::AX_ROLE_FORM: + // TODO(dougt) why not just use the html_tag? + return "form"; + + case ui::AX_ROLE_HEADING: + if (!html_tag.empty()) + return html_tag; + break; + + case ui::AX_ROLE_PARAGRAPH: + // TODO(dougt) why not just use the html_tag and why upper case? + return "P"; + + case ui::AX_ROLE_GENERIC_CONTAINER: + // TODO(dougt) why can't we always use div in this case? + if (html_tag.empty()) + return "div"; + return html_tag; + + case ui::AX_ROLE_SWITCH: + return "switch"; + + default: + return ""; + } + + return ""; +} + int AXPlatformNodeWin::MSAAState() { const AXNodeData& data = GetData(); const uint32_t state = data.state;
diff --git a/ui/accessibility/platform/ax_platform_node_win.h b/ui/accessibility/platform/ax_platform_node_win.h index 8120b5e..645e686b 100644 --- a/ui/accessibility/platform/ax_platform_node_win.h +++ b/ui/accessibility/platform/ax_platform_node_win.h
@@ -274,6 +274,8 @@ private: int MSAARole(); + std::string StringOverrideForMSAARole(); + int MSAAState(); int MSAAEvent(ui::AXEvent event);
diff --git a/ui/app_list/BUILD.gn b/ui/app_list/BUILD.gn index dd99897..ce45400 100644 --- a/ui/app_list/BUILD.gn +++ b/ui/app_list/BUILD.gn
@@ -140,6 +140,8 @@ "views/search_result_actions_view.cc", "views/search_result_actions_view.h", "views/search_result_actions_view_delegate.h", + "views/search_result_answer_card_view.cc", + "views/search_result_answer_card_view.h", "views/search_result_container_view.cc", "views/search_result_container_view.h", "views/search_result_list_view.cc",
diff --git a/ui/app_list/views/app_list_item_view.cc b/ui/app_list/views/app_list_item_view.cc index 8df2df4..488aef3 100644 --- a/ui/app_list/views/app_list_item_view.cc +++ b/ui/app_list/views/app_list_item_view.cc
@@ -227,58 +227,6 @@ progress_bar_->SetValue(percent_downloaded / 100.0); } -const char* AppListItemView::GetClassName() const { - return kViewClassName; -} - -void AppListItemView::Layout() { - gfx::Rect rect(GetContentsBounds()); - - const int left_right_padding = - title_->font_list().GetExpectedTextWidth(kLeftRightPaddingChars); - rect.Inset(left_right_padding, kTopPadding, left_right_padding, 0); - const int y = rect.y(); - - icon_->SetBoundsRect(GetIconBoundsForTargetViewBounds(GetContentsBounds())); - - const gfx::Size title_size = title_->GetPreferredSize(); - gfx::Rect title_bounds(rect.x() + (rect.width() - title_size.width()) / 2, - y + kGridIconDimension + kIconTitleSpacing, - title_size.width(), - title_size.height()); - title_bounds.Intersect(rect); - title_->SetBoundsRect(title_bounds); - SetTitleSubpixelAA(); - - gfx::Rect progress_bar_bounds(progress_bar_->GetPreferredSize()); - progress_bar_bounds.set_x( - (GetContentsBounds().width() - progress_bar_bounds.width()) / 2); - progress_bar_bounds.set_y(title_bounds.y()); - progress_bar_->SetBoundsRect(progress_bar_bounds); -} - -void AppListItemView::OnPaint(gfx::Canvas* canvas) { - if (apps_grid_view_->IsDraggedView(this)) - return; - - gfx::Rect rect(GetContentsBounds()); - if (apps_grid_view_->IsSelectedView(this)) - canvas->FillRect(rect, kSelectedColor); - - if (ui_state_ == UI_STATE_DROPPING_IN_FOLDER) { - DCHECK(apps_grid_view_->model()->folders_enabled()); - - // Draw folder dropping preview circle. - gfx::Point center = gfx::Point(icon_->x() + icon_->size().width() / 2, - icon_->y() + icon_->size().height() / 2); - cc::PaintFlags flags; - flags.setStyle(cc::PaintFlags::kFill_Style); - flags.setAntiAlias(true); - flags.setColor(kFolderBubbleColor); - canvas->DrawCircle(center, kFolderPreviewRadius, flags); - } -} - void AppListItemView::ShowContextMenuForView(views::View* source, const gfx::Point& point, ui::MenuSourceType source_type) { @@ -321,6 +269,28 @@ return views::CustomButton::ShouldEnterPushedState(event); } +void AppListItemView::PaintButtonContents(gfx::Canvas* canvas) { + if (apps_grid_view_->IsDraggedView(this)) + return; + + gfx::Rect rect(GetContentsBounds()); + if (apps_grid_view_->IsSelectedView(this)) + canvas->FillRect(rect, kSelectedColor); + + if (ui_state_ == UI_STATE_DROPPING_IN_FOLDER) { + DCHECK(apps_grid_view_->model()->folders_enabled()); + + // Draw folder dropping preview circle. + gfx::Point center = gfx::Point(icon_->x() + icon_->size().width() / 2, + icon_->y() + icon_->size().height() / 2); + cc::PaintFlags flags; + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setAntiAlias(true); + flags.setColor(kFolderBubbleColor); + canvas->DrawCircle(center, kFolderPreviewRadius, flags); + } +} + bool AppListItemView::OnMousePressed(const ui::MouseEvent& event) { CustomButton::OnMousePressed(event); @@ -337,6 +307,35 @@ return true; } +const char* AppListItemView::GetClassName() const { + return kViewClassName; +} + +void AppListItemView::Layout() { + gfx::Rect rect(GetContentsBounds()); + + const int left_right_padding = + title_->font_list().GetExpectedTextWidth(kLeftRightPaddingChars); + rect.Inset(left_right_padding, kTopPadding, left_right_padding, 0); + const int y = rect.y(); + + icon_->SetBoundsRect(GetIconBoundsForTargetViewBounds(GetContentsBounds())); + + const gfx::Size title_size = title_->GetPreferredSize(); + gfx::Rect title_bounds(rect.x() + (rect.width() - title_size.width()) / 2, + y + kGridIconDimension + kIconTitleSpacing, + title_size.width(), title_size.height()); + title_bounds.Intersect(rect); + title_->SetBoundsRect(title_bounds); + SetTitleSubpixelAA(); + + gfx::Rect progress_bar_bounds(progress_bar_->GetPreferredSize()); + progress_bar_bounds.set_x( + (GetContentsBounds().width() - progress_bar_bounds.width()) / 2); + progress_bar_bounds.set_y(title_bounds.y()); + progress_bar_->SetBoundsRect(progress_bar_bounds); +} + bool AppListItemView::OnKeyPressed(const ui::KeyEvent& event) { // Disable space key to press the button. The keyboard events received // by this view are forwarded from a Textfield (SearchBoxView) and key
diff --git a/ui/app_list/views/app_list_item_view.h b/ui/app_list/views/app_list_item_view.h index 191f182..9670438 100644 --- a/ui/app_list/views/app_list_item_view.h +++ b/ui/app_list/views/app_list_item_view.h
@@ -114,11 +114,6 @@ // Invoked when |mouse_drag_timer_| fires to show dragging UI. void OnMouseDragTimer(); - // views::View overrides: - const char* GetClassName() const override; - void Layout() override; - void OnPaint(gfx::Canvas* canvas) override; - // views::ContextMenuController overrides: void ShowContextMenuForView(views::View* source, const gfx::Point& point, @@ -127,8 +122,11 @@ // views::CustomButton overrides: void StateChanged(ButtonState old_state) override; bool ShouldEnterPushedState(const ui::Event& event) override; + void PaintButtonContents(gfx::Canvas* canvas) override; // views::View overrides: + const char* GetClassName() const override; + void Layout() override; bool OnKeyPressed(const ui::KeyEvent& event) override; bool OnMousePressed(const ui::MouseEvent& event) override; void OnMouseReleased(const ui::MouseEvent& event) override;
diff --git a/ui/app_list/views/contents_view.cc b/ui/app_list/views/contents_view.cc index aad1125..bb8218b 100644 --- a/ui/app_list/views/contents_view.cc +++ b/ui/app_list/views/contents_view.cc
@@ -17,56 +17,23 @@ #include "ui/app_list/views/apps_grid_view.h" #include "ui/app_list/views/custom_launcher_page_view.h" #include "ui/app_list/views/search_box_view.h" +#include "ui/app_list/views/search_result_answer_card_view.h" #include "ui/app_list/views/search_result_list_view.h" #include "ui/app_list/views/search_result_page_view.h" #include "ui/app_list/views/search_result_tile_item_list_view.h" #include "ui/app_list/views/start_page_view.h" #include "ui/events/event.h" -#include "ui/views/layout/box_layout.h" #include "ui/views/view_model.h" #include "ui/views/widget/widget.h" namespace app_list { -namespace { - -// Container of the search answer view. -class SearchAnswerContainerView : public views::View { - public: - explicit SearchAnswerContainerView(views::View* search_results_page_view) - : search_results_page_view_(search_results_page_view) { - views::BoxLayout* answer_container_layout = - new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); - answer_container_layout->set_main_axis_alignment( - views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER); - SetLayoutManager(answer_container_layout); - } - - // views::View overrides: - void ChildPreferredSizeChanged(View* child) override { - if (visible()) - search_results_page_view_->Layout(); - } - - const char* GetClassName() const override { - return "SearchAnswerContainerView"; - } - - private: - views::View* const search_results_page_view_; - - DISALLOW_COPY_AND_ASSIGN(SearchAnswerContainerView); -}; - -} // namespace - ContentsView::ContentsView(AppListMainView* app_list_main_view) : model_(nullptr), apps_container_view_(nullptr), search_results_page_view_(nullptr), start_page_view_(nullptr), custom_page_view_(nullptr), - search_answer_container_view_(nullptr), app_list_main_view_(app_list_main_view), page_before_search_(0) { pagination_model_.SetTransitionDurations(kPageTransitionDurationInMs, @@ -76,8 +43,6 @@ ContentsView::~ContentsView() { pagination_model_.RemoveObserver(this); - if (model_) - model_->RemoveObserver(this); } void ContentsView::Init(AppListModel* model) { @@ -104,14 +69,14 @@ // Search results UI. search_results_page_view_ = new SearchResultPageView(); - // Search answer container UI. - search_answer_container_view_ = - new SearchAnswerContainerView(search_results_page_view_); - search_answer_container_view_->SetVisible(false); - views::View* search_answer_view = view_delegate->GetSearchAnswerWebView(); - if (search_answer_view) - search_answer_container_view_->AddChildView(search_answer_view); - search_results_page_view_->AddChildView(search_answer_container_view_); + // Search result containers. + views::View* const search_answer_view = + view_delegate->GetSearchAnswerWebView(); + if (search_answer_view) { + search_results_page_view_->AddSearchResultContainerView( + nullptr, new SearchResultAnswerCardView( + model_, search_results_page_view_, search_answer_view)); + } AppListModel::SearchResults* results = view_delegate->GetModel()->results(); search_results_page_view_->AddSearchResultContainerView( @@ -142,8 +107,6 @@ pagination_model_.SelectPage(initial_page_index, false); ActivePageChanged(); - - model_->AddObserver(this); } void ContentsView::CancelDrag() { @@ -524,12 +487,4 @@ UpdatePageBounds(); } -void ContentsView::OnSearchAnswerAvailableChanged(bool has_answer) { - if (has_answer == search_answer_container_view_->visible()) - return; - - search_answer_container_view_->SetVisible(has_answer); - search_results_page_view_->Layout(); -} - } // namespace app_list
diff --git a/ui/app_list/views/contents_view.h b/ui/app_list/views/contents_view.h index 435ff00..62a52cd2 100644 --- a/ui/app_list/views/contents_view.h +++ b/ui/app_list/views/contents_view.h
@@ -13,7 +13,6 @@ #include "base/macros.h" #include "ui/app_list/app_list_export.h" #include "ui/app_list/app_list_model.h" -#include "ui/app_list/app_list_model_observer.h" #include "ui/app_list/pagination_model.h" #include "ui/app_list/pagination_model_observer.h" #include "ui/views/view.h" @@ -43,8 +42,7 @@ // interface for switching between launcher pages, and animates the transition // between them. class APP_LIST_EXPORT ContentsView : public views::View, - public PaginationModelObserver, - public AppListModelObserver { + public PaginationModelObserver { public: explicit ContentsView(AppListMainView* app_list_main_view); ~ContentsView() override; @@ -136,9 +134,6 @@ void TransitionStarted() override; void TransitionChanged() override; - // Overridden from AppListModelObserver: - void OnSearchAnswerAvailableChanged(bool has_answer) override; - private: // Sets the active launcher page, accounting for whether the change is for // search results. @@ -190,10 +185,6 @@ StartPageView* start_page_view_; CustomLauncherPageView* custom_page_view_; - // Unowned pointer to the container of the search answer web view. This - // container view is a sub-view of search_results_page_view_. - View* search_answer_container_view_; - // The child page views. Owned by the views hierarchy. std::vector<AppListPage*> app_list_pages_;
diff --git a/ui/app_list/views/page_switcher.cc b/ui/app_list/views/page_switcher.cc index eb08075..4f9a649a 100644 --- a/ui/app_list/views/page_switcher.cc +++ b/ui/app_list/views/page_switcher.cc
@@ -54,14 +54,13 @@ return gfx::Size(button_width_, kButtonHeight); } - void OnPaint(gfx::Canvas* canvas) override { + void PaintButtonContents(gfx::Canvas* canvas) override { if (state() == STATE_HOVERED) PaintButton(canvas, kPagerHoverColor); else PaintButton(canvas, kPagerNormalColor); } - private: void OnGestureEvent(ui::GestureEvent* event) override { CustomButton::OnGestureEvent(event); @@ -73,6 +72,7 @@ SchedulePaint(); } + private: // Paints a button that has two rounded corner at bottom. void PaintButton(gfx::Canvas* canvas, SkColor base_color) { gfx::Rect rect(GetContentsBounds());
diff --git a/ui/app_list/views/search_result_answer_card_view.cc b/ui/app_list/views/search_result_answer_card_view.cc new file mode 100644 index 0000000..89078c0 --- /dev/null +++ b/ui/app_list/views/search_result_answer_card_view.cc
@@ -0,0 +1,144 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/app_list/views/search_result_answer_card_view.h" + +#include "ui/app_list/app_list_constants.h" +#include "ui/app_list/app_list_features.h" +#include "ui/app_list/views/search_result_page_view.h" +#include "ui/views/background.h" +#include "ui/views/controls/button/custom_button.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/layout/fill_layout.h" + +namespace app_list { + +namespace { + +// Answer card relevance is high to always have it first. +constexpr double kSearchAnswerCardRelevance = 100; + +// Container of the search answer view. +class SearchAnswerContainerView : public views::CustomButton { + public: + explicit SearchAnswerContainerView(views::View* search_results_page_view) + : CustomButton(nullptr), + search_results_page_view_(search_results_page_view) { + // Center the card horizontally in the container. + views::BoxLayout* answer_container_layout = + new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); + answer_container_layout->set_main_axis_alignment( + views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER); + SetLayoutManager(answer_container_layout); + } + + void SetSelected(bool selected) { + if (selected == selected_) + return; + selected_ = selected; + UpdateBackgroundColor(); + } + + // views::CustomButton overrides: + void ChildPreferredSizeChanged(View* child) override { + // Card size changed. + if (visible()) + search_results_page_view_->Layout(); + } + + int GetHeightForWidth(int w) const override { + return visible() ? CustomButton::GetHeightForWidth(w) : 0; + } + + const char* GetClassName() const override { + return "SearchAnswerContainerView"; + } + + void StateChanged(ButtonState old_state) override { UpdateBackgroundColor(); } + + private: + void UpdateBackgroundColor() { + views::Background* background = nullptr; + + if (selected_) { + background = views::Background::CreateSolidBackground(kSelectedColor); + } else if (state() == STATE_HOVERED || state() == STATE_PRESSED) { + background = views::Background::CreateSolidBackground(kHighlightedColor); + } + + set_background(background); + SchedulePaint(); + } + + views::View* const search_results_page_view_; + bool selected_ = false; + + DISALLOW_COPY_AND_ASSIGN(SearchAnswerContainerView); +}; + +} // namespace + +SearchResultAnswerCardView::SearchResultAnswerCardView( + AppListModel* model, + SearchResultPageView* search_results_page_view, + views::View* search_answer_view) + : model_(model), + search_answer_container_view_( + new SearchAnswerContainerView(search_results_page_view)) { + search_answer_container_view_->SetVisible(false); + search_answer_container_view_->AddChildView(search_answer_view); + AddChildView(search_answer_container_view_); + model->AddObserver(this); + SetLayoutManager(new views::FillLayout); +} + +SearchResultAnswerCardView::~SearchResultAnswerCardView() { + model_->RemoveObserver(this); +} + +const char* SearchResultAnswerCardView::GetClassName() const { + return "SearchResultAnswerCardView"; +} + +void SearchResultAnswerCardView::OnContainerSelected( + bool from_bottom, + bool directional_movement) { + if (num_results() == 0) + return; + + SetSelectedIndex(0); +} + +int SearchResultAnswerCardView::GetYSize() { + return num_results(); +} + +int SearchResultAnswerCardView::DoUpdate() { + const bool have_result = search_answer_container_view_->visible(); + set_container_score(have_result ? kSearchAnswerCardRelevance : 0); + return have_result ? 1 : 0; +} + +void SearchResultAnswerCardView::UpdateSelectedIndex(int old_selected, + int new_selected) { + if (new_selected == old_selected) + return; + + const bool is_selected = new_selected == 0; + search_answer_container_view_->SetSelected(is_selected); + if (is_selected) + NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true); +} + +void SearchResultAnswerCardView::OnSearchAnswerAvailableChanged( + bool has_answer) { + const bool visible = has_answer && !features::IsAnswerCardDarkRunEnabled(); + if (visible == search_answer_container_view_->visible()) + return; + + search_answer_container_view_->SetVisible(visible); + ScheduleUpdate(); +} + +} // namespace app_list
diff --git a/ui/app_list/views/search_result_answer_card_view.h b/ui/app_list/views/search_result_answer_card_view.h new file mode 100644 index 0000000..8c985f0 --- /dev/null +++ b/ui/app_list/views/search_result_answer_card_view.h
@@ -0,0 +1,57 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_APP_LIST_VIEWS_SEARCH_RESULT_ANSWER_CARD_VIEW_H_ +#define UI_APP_LIST_VIEWS_SEARCH_RESULT_ANSWER_CARD_VIEW_H_ + +#include "ui/app_list/app_list_model_observer.h" +#include "ui/app_list/views/search_result_container_view.h" + +namespace app_list { + +class AppListModel; +class SearchResultPageView; + +namespace { +class SearchAnswerContainerView; +} + +// Result container for the search answer card. +class APP_LIST_EXPORT SearchResultAnswerCardView + : public SearchResultContainerView, + public AppListModelObserver { + public: + SearchResultAnswerCardView(AppListModel* model, + SearchResultPageView* search_results_page_view, + views::View* search_answer_view); + ~SearchResultAnswerCardView() override; + + private: + // Overridden from views::View: + const char* GetClassName() const override; + + // Overridden from SearchResultContainerView: + void OnContainerSelected(bool from_bottom, + bool directional_movement) override; + void NotifyFirstResultYIndex(int y_index) override {} + int GetYSize() override; + int DoUpdate() override; + void UpdateSelectedIndex(int old_selected, int new_selected) override; + + // Overridden from AppListModelObserver + void OnSearchAnswerAvailableChanged(bool has_answer) override; + + // Unowned pointer to application list model. + AppListModel* const model_; + + // Pointer to the container of the search answer; owned by the view hierarchy. + // It's visible iff we have a search answer result. + SearchAnswerContainerView* const search_answer_container_view_; + + DISALLOW_COPY_AND_ASSIGN(SearchResultAnswerCardView); +}; + +} // namespace app_list + +#endif // UI_APP_LIST_VIEWS_SEARCH_RESULT_ANSWER_CARD_VIEW_H_
diff --git a/ui/app_list/views/search_result_container_view.h b/ui/app_list/views/search_result_container_view.h index b5f8496..19c02c13 100644 --- a/ui/app_list/views/search_result_container_view.h +++ b/ui/app_list/views/search_result_container_view.h
@@ -84,11 +84,12 @@ virtual void OnContainerSelected(bool from_bottom, bool directional_movement) = 0; - private: + protected: // Schedules an Update call using |update_factory_|. Do nothing if there is a // pending call. void ScheduleUpdate(); + private: // Updates UI with model. Returns the number of visible results. virtual int DoUpdate() = 0;
diff --git a/ui/app_list/views/search_result_view.cc b/ui/app_list/views/search_result_view.cc index 678579d..320585d 100644 --- a/ui/app_list/views/search_result_view.cc +++ b/ui/app_list/views/search_result_view.cc
@@ -240,7 +240,7 @@ Layout(); } -void SearchResultView::OnPaint(gfx::Canvas* canvas) { +void SearchResultView::PaintButtonContents(gfx::Canvas* canvas) { gfx::Rect rect(GetContentsBounds()); if (rect.IsEmpty()) return;
diff --git a/ui/app_list/views/search_result_view.h b/ui/app_list/views/search_result_view.h index c9f697c9..dee91d4 100644 --- a/ui/app_list/views/search_result_view.h +++ b/ui/app_list/views/search_result_view.h
@@ -80,7 +80,7 @@ void Layout() override; bool OnKeyPressed(const ui::KeyEvent& event) override; void ChildPreferredSizeChanged(views::View* child) override; - void OnPaint(gfx::Canvas* canvas) override; + void PaintButtonContents(gfx::Canvas* canvas) override; // views::ButtonListener overrides: void ButtonPressed(views::Button* sender, const ui::Event& event) override;
diff --git a/ui/aura/mus/client_surface_embedder.cc b/ui/aura/mus/client_surface_embedder.cc index 94ad333..4458206 100644 --- a/ui/aura/mus/client_surface_embedder.cc +++ b/ui/aura/mus/client_surface_embedder.cc
@@ -6,6 +6,7 @@ #include "cc/surfaces/surface_reference_factory.h" #include "ui/aura/window.h" +#include "ui/gfx/geometry/dip_util.h" namespace aura { namespace { @@ -65,22 +66,26 @@ void ClientSurfaceEmbedder::UpdateSizeAndGutters() { surface_layer_->SetBounds(gfx::Rect(window_->bounds().size())); - // TODO(fsamuel): Fix this for high DPI. - gfx::Size fallback_surface_size( - surface_layer_->GetFallbackSurfaceInfo() - ? surface_layer_->GetFallbackSurfaceInfo()->size_in_pixels() - : gfx::Size()); + gfx::Size fallback_surface_size_in_dip; + const cc::SurfaceInfo* fallback_surface_info = + surface_layer_->GetFallbackSurfaceInfo(); + if (fallback_surface_info) { + float fallback_device_scale_factor = + fallback_surface_info->device_scale_factor(); + fallback_surface_size_in_dip = gfx::ConvertSizeToDIP( + fallback_device_scale_factor, fallback_surface_info->size_in_pixels()); + } gfx::Rect window_bounds(window_->bounds()); - if (fallback_surface_size.width() < window_bounds.width()) { + if (fallback_surface_size_in_dip.width() < window_bounds.width()) { right_gutter_ = base::MakeUnique<ui::Layer>(ui::LAYER_SOLID_COLOR); // TODO(fsamuel): Use the embedded client's background color. right_gutter_->SetColor(SK_ColorWHITE); - int width = window_bounds.width() - fallback_surface_size.width(); + int width = window_bounds.width() - fallback_surface_size_in_dip.width(); // The right gutter also includes the bottom-right corner, if necessary. int height = window_bounds.height() - client_area_insets_.height(); - right_gutter_->SetBounds( - gfx::Rect(client_area_insets_.left() + fallback_surface_size.width(), - client_area_insets_.top(), width, height)); + right_gutter_->SetBounds(gfx::Rect( + client_area_insets_.left() + fallback_surface_size_in_dip.width(), + client_area_insets_.top(), width, height)); window_->layer()->Add(right_gutter_.get()); } else { right_gutter_.reset(); @@ -88,15 +93,15 @@ // Only create a bottom gutter if a fallback surface is available. Otherwise, // the right gutter will fill the whole window until a fallback is available. - if (!fallback_surface_size.IsEmpty() && - fallback_surface_size.height() < window_bounds.height()) { + if (!fallback_surface_size_in_dip.IsEmpty() && + fallback_surface_size_in_dip.height() < window_bounds.height()) { bottom_gutter_ = base::MakeUnique<ui::Layer>(ui::LAYER_SOLID_COLOR); // TODO(fsamuel): Use the embedded client's background color. bottom_gutter_->SetColor(SK_ColorWHITE); - int width = fallback_surface_size.width(); - int height = window_bounds.height() - fallback_surface_size.height(); + int width = fallback_surface_size_in_dip.width(); + int height = window_bounds.height() - fallback_surface_size_in_dip.height(); bottom_gutter_->SetBounds( - gfx::Rect(0, fallback_surface_size.height(), width, height)); + gfx::Rect(0, fallback_surface_size_in_dip.height(), width, height)); window_->layer()->Add(bottom_gutter_.get()); } else { bottom_gutter_.reset();
diff --git a/ui/aura/mus/window_port_mus.cc b/ui/aura/mus/window_port_mus.cc index 7f2a083..e550ddb 100644 --- a/ui/aura/mus/window_port_mus.cc +++ b/ui/aura/mus/window_port_mus.cc
@@ -17,6 +17,7 @@ #include "ui/base/class_property.h" #include "ui/display/display.h" #include "ui/display/screen.h" +#include "ui/gfx/geometry/dip_util.h" namespace aura { @@ -230,7 +231,9 @@ ServerChangeData data; data.bounds_in_dip = bounds; ScopedServerChange change(this, ServerChangeType::BOUNDS, data); - last_surface_size_ = bounds.size(); + float device_scale_factor = ScaleFactorForDisplay(window_); + last_surface_size_in_pixels_ = + gfx::ConvertSizeToPixel(device_scale_factor, bounds.size()); if (local_surface_id) local_surface_id_ = *local_surface_id; else @@ -284,12 +287,14 @@ } const cc::LocalSurfaceId& WindowPortMus::GetOrAllocateLocalSurfaceId( - const gfx::Size& surface_size) { - if (last_surface_size_ == surface_size && local_surface_id_.is_valid()) + const gfx::Size& surface_size_in_pixels) { + if (last_surface_size_in_pixels_ == surface_size_in_pixels && + local_surface_id_.is_valid()) { return local_surface_id_; + } local_surface_id_ = local_surface_id_allocator_.GenerateId(); - last_surface_size_ = surface_size; + last_surface_size_in_pixels_ = surface_size_in_pixels; // If the FrameSinkId is available, then immediately embed the SurfaceId. // The newly generated frame by the embedder will block in the display @@ -533,9 +538,9 @@ if (!frame_sink_id_.is_valid() || !local_surface_id_.is_valid()) return; - SetPrimarySurfaceInfo( - cc::SurfaceInfo(cc::SurfaceId(frame_sink_id_, local_surface_id_), - ScaleFactorForDisplay(window_), last_surface_size_)); + SetPrimarySurfaceInfo(cc::SurfaceInfo( + cc::SurfaceId(frame_sink_id_, local_surface_id_), + ScaleFactorForDisplay(window_), last_surface_size_in_pixels_)); } void WindowPortMus::UpdateClientSurfaceEmbedder() {
diff --git a/ui/aura/mus/window_port_mus.h b/ui/aura/mus/window_port_mus.h index 70f8dcd..c72fb58 100644 --- a/ui/aura/mus/window_port_mus.h +++ b/ui/aura/mus/window_port_mus.h
@@ -222,7 +222,7 @@ const std::vector<uint8_t>* property_data) override; void SetFrameSinkIdFromServer(const cc::FrameSinkId& frame_sink_id) override; const cc::LocalSurfaceId& GetOrAllocateLocalSurfaceId( - const gfx::Size& surface_size) override; + const gfx::Size& surface_size_in_pixels) override; void SetPrimarySurfaceInfo(const cc::SurfaceInfo& surface_info) override; void SetFallbackSurfaceInfo(const cc::SurfaceInfo& surface_info) override; void DestroyFromServer() override; @@ -281,7 +281,7 @@ cc::LocalSurfaceId local_surface_id_; cc::LocalSurfaceIdAllocator local_surface_id_allocator_; - gfx::Size last_surface_size_; + gfx::Size last_surface_size_in_pixels_; ui::CursorData cursor_;
diff --git a/ui/aura/mus/window_tree_client_unittest.cc b/ui/aura/mus/window_tree_client_unittest.cc index a2b76d0..3e8b5d87 100644 --- a/ui/aura/mus/window_tree_client_unittest.cc +++ b/ui/aura/mus/window_tree_client_unittest.cc
@@ -104,16 +104,19 @@ using WindowTreeClientWmTest = test::AuraMusWmTestBase; using WindowTreeClientClientTest = test::AuraMusClientTestBase; -// WindowTreeClientWmTest with --enable-surface-synchronization. -class WindowTreeClientWmTestSurfaceSync : public WindowTreeClientWmTest { +class WindowTreeClientWmTestSurfaceSync + : public WindowTreeClientWmTest, + public ::testing::WithParamInterface<bool> { public: WindowTreeClientWmTestSurfaceSync() {} ~WindowTreeClientWmTestSurfaceSync() override {} // WindowTreeClientWmTest: void SetUp() override { - base::CommandLine::ForCurrentProcess()->AppendSwitch( - cc::switches::kEnableSurfaceSynchronization); + if (GetParam()) { + base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( + switches::kForceDeviceScaleFactor, "2"); + } WindowTreeClientWmTest::SetUp(); } @@ -204,9 +207,13 @@ EXPECT_FALSE(window_mus->GetLocalSurfaceId().is_valid()); } +INSTANTIATE_TEST_CASE_P(/* no prefix */, + WindowTreeClientWmTestSurfaceSync, + ::testing::Bool()); + // Verifies that a ClientSurfaceEmbedder is created for a window once it has // a bounds, and a valid FrameSinkId. -TEST_F(WindowTreeClientWmTestSurfaceSync, +TEST_P(WindowTreeClientWmTestSurfaceSync, ClientSurfaceEmbedderOnValidEmbedding) { Window window(nullptr); // TOP_LEVEL_IN_WM and EMBED_IN_OWNER windows allocate cc::LocalSurfaceIds @@ -219,7 +226,7 @@ WindowMus* window_mus = WindowMus::Get(&window); ASSERT_NE(nullptr, window_mus); EXPECT_FALSE(window_mus->GetLocalSurfaceId().is_valid()); - const gfx::Rect new_bounds(gfx::Rect(0, 0, 100, 100)); + gfx::Rect new_bounds(gfx::Rect(0, 0, 100, 100)); ASSERT_NE(new_bounds, window.bounds()); window.SetBounds(new_bounds); EXPECT_EQ(new_bounds, window.bounds()); @@ -240,12 +247,14 @@ ASSERT_NE(nullptr, client_surface_embedder); // Until the fallback surface fills the window, we will have gutter. - ui::Layer* right_gutter = client_surface_embedder->RightGutterForTesting(); - ASSERT_NE(nullptr, right_gutter); - EXPECT_EQ(gfx::Rect(100, 100), right_gutter->bounds()); - // We don't have a bottom gutter if the fallback surface size is (0, 0) as the - // right gutter will fill the whole area. - ASSERT_EQ(nullptr, client_surface_embedder->BottomGutterForTesting()); + { + ui::Layer* right_gutter = client_surface_embedder->RightGutterForTesting(); + ASSERT_NE(nullptr, right_gutter); + EXPECT_EQ(gfx::Rect(100, 100), right_gutter->bounds()); + // We don't have a bottom gutter if the fallback surface size is (0, 0) as + // the right gutter will fill the whole area. + ASSERT_EQ(nullptr, client_surface_embedder->BottomGutterForTesting()); + } // When a SurfaceInfo arrives from the window server, we use it as the // fallback SurfaceInfo. Here we issue the PrimarySurfaceInfo back to the @@ -256,11 +265,30 @@ // The gutter is gone. ASSERT_EQ(nullptr, client_surface_embedder->BottomGutterForTesting()); ASSERT_EQ(nullptr, client_surface_embedder->RightGutterForTesting()); + + // Resize again: we should have gutter. + new_bounds.SetRect(0, 0, 150, 150); + ASSERT_NE(new_bounds, window.bounds()); + window.SetBounds(new_bounds); + ASSERT_NE(nullptr, client_surface_embedder->BottomGutterForTesting()); + ASSERT_NE(nullptr, client_surface_embedder->RightGutterForTesting()); + + // Until the fallback surface fills the window, we will have gutter. + { + ui::Layer* right_gutter = client_surface_embedder->RightGutterForTesting(); + ASSERT_NE(nullptr, right_gutter); + EXPECT_EQ(gfx::Rect(100, 0, 50, 150), right_gutter->bounds()); + + ui::Layer* bottom_gutter = + client_surface_embedder->BottomGutterForTesting(); + ASSERT_NE(nullptr, bottom_gutter); + EXPECT_EQ(gfx::Rect(0, 100, 100, 50), bottom_gutter->bounds()); + } } // Verifies that the cc::LocalSurfaceId generated by an embedder changes when // the size changes, but not when the position changes. -TEST_F(WindowTreeClientWmTest, SetBoundsLocalSurfaceIdChanges) { +TEST_P(WindowTreeClientWmTestSurfaceSync, SetBoundsLocalSurfaceIdChanges) { ASSERT_EQ(base::nullopt, window_tree()->last_local_surface_id()); Window window(nullptr); // TOP_LEVEL_IN_WM and EMBED_IN_OWNER windows allocate cc::LocalSurfaceIds
diff --git a/ui/gl/gl_image_dxgi.cc b/ui/gl/gl_image_dxgi.cc index a470f33..a7ab19c 100644 --- a/ui/gl/gl_image_dxgi.cc +++ b/ui/gl/gl_image_dxgi.cc
@@ -118,6 +118,10 @@ base::win::ScopedComPtr<ID3D11DeviceContext> context; d3d11_device_->GetImmediateContext(context.GetAddressOf()); context.CopyTo(video_context_.GetAddressOf()); + + base::win::ScopedComPtr<ID3D10Multithread> multithread; + d3d11_device_.CopyTo(multithread.GetAddressOf()); + CHECK(multithread->GetMultithreadProtected()); return true; } @@ -126,6 +130,10 @@ const base::win::ScopedComPtr<ID3D11VideoProcessorEnumerator>& enumerator) { output_view_.Reset(); + base::win::ScopedComPtr<ID3D11Device> processor_device; + video_processor->GetDevice(processor_device.GetAddressOf()); + CHECK_EQ(d3d11_device_.Get(), processor_device.Get()); + d3d11_processor_ = video_processor; enumerator_ = enumerator; D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC output_view_desc = { @@ -150,6 +158,11 @@ if (copied_) return true; + CHECK(video_device_); + base::win::ScopedComPtr<ID3D11Device> texture_device; + texture_->GetDevice(texture_device.GetAddressOf()); + CHECK_EQ(d3d11_device_.Get(), texture_device.Get()); + D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC input_view_desc = {0}; input_view_desc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D; input_view_desc.Texture2D.ArraySlice = (UINT)level_;
diff --git a/ui/message_center/views/notification_button.cc b/ui/message_center/views/notification_button.cc index 72b2be7..4fd8ac6a 100644 --- a/ui/message_center/views/notification_button.cc +++ b/ui/message_center/views/notification_button.cc
@@ -17,12 +17,7 @@ namespace message_center { NotificationButton::NotificationButton(views::ButtonListener* listener) - : views::CustomButton(listener), - icon_(NULL), - title_(NULL), - focus_painter_(views::Painter::CreateSolidFocusPainter( - message_center::kFocusBorderColor, - gfx::Insets(1, 2, 2, 2))) { + : views::CustomButton(listener), icon_(NULL), title_(NULL) { SetFocusForPlatform(); // Create a background so that it does not change when the MessageView // background changes to show touch feedback @@ -34,6 +29,8 @@ message_center::kButtonHorizontalPadding, kButtonVecticalPadding, message_center::kButtonIconToTitlePadding)); + SetFocusPainter(views::Painter::CreateSolidFocusPainter( + message_center::kFocusBorderColor, gfx::Insets(1, 2, 2, 2))); } NotificationButton::~NotificationButton() { @@ -83,22 +80,9 @@ return message_center::kButtonHeight; } -void NotificationButton::OnPaint(gfx::Canvas* canvas) { - CustomButton::OnPaint(canvas); - views::Painter::PaintFocusPainter(this, canvas, focus_painter_.get()); -} - void NotificationButton::OnFocus() { views::CustomButton::OnFocus(); ScrollRectToVisible(GetLocalBounds()); - // We render differently when focused. - SchedulePaint(); - } - -void NotificationButton::OnBlur() { - views::CustomButton::OnBlur(); - // We render differently when focused. - SchedulePaint(); } void NotificationButton::ViewHierarchyChanged(
diff --git a/ui/message_center/views/notification_button.h b/ui/message_center/views/notification_button.h index 69f80bae..3d3d218 100644 --- a/ui/message_center/views/notification_button.h +++ b/ui/message_center/views/notification_button.h
@@ -30,9 +30,7 @@ // Overridden from views::View: gfx::Size CalculatePreferredSize() const override; int GetHeightForWidth(int width) const override; - void OnPaint(gfx::Canvas* canvas) override; void OnFocus() override; - void OnBlur() override; void ViewHierarchyChanged( const ViewHierarchyChangedDetails& details) override; @@ -42,7 +40,6 @@ private: views::ImageView* icon_; views::Label* title_; - std::unique_ptr<views::Painter> focus_painter_; DISALLOW_COPY_AND_ASSIGN(NotificationButton); };
diff --git a/ui/views/controls/button/blue_button_unittest.cc b/ui/views/controls/button/blue_button_unittest.cc index a4292ca..657f5bfa 100644 --- a/ui/views/controls/button/blue_button_unittest.cc +++ b/ui/views/controls/button/blue_button_unittest.cc
@@ -27,12 +27,12 @@ LabelButton* button = new LabelButton(nullptr, base::ASCIIToUTF16("foo")); EXPECT_EQ(Button::STYLE_TEXTBUTTON, button->style()); // Focus painter by default. - EXPECT_TRUE(button->focus_painter()); + EXPECT_TRUE(button->focus_painter_.get()); // Switch to the same style as BlueButton for a more compelling comparison. button->SetStyleDeprecated(Button::STYLE_BUTTON); EXPECT_EQ(Button::STYLE_BUTTON, button->style()); - EXPECT_FALSE(button->focus_painter()); + EXPECT_FALSE(button->focus_painter_.get()); widget->GetContentsView()->AddChildView(button); button->SizeToPreferredSize(); @@ -47,7 +47,7 @@ // ... a special blue border should be used. BlueButton* blue_button = new BlueButton(nullptr, base::ASCIIToUTF16("foo")); EXPECT_EQ(Button::STYLE_BUTTON, blue_button->style()); - EXPECT_FALSE(blue_button->focus_painter()); + EXPECT_FALSE(blue_button->focus_painter_.get()); widget->GetContentsView()->AddChildView(blue_button); blue_button->SizeToPreferredSize();
diff --git a/ui/views/controls/button/checkbox.cc b/ui/views/controls/button/checkbox.cc index 52a5d69..6e2dccd 100644 --- a/ui/views/controls/button/checkbox.cc +++ b/ui/views/controls/button/checkbox.cc
@@ -125,23 +125,6 @@ } } -void Checkbox::OnPaint(gfx::Canvas* canvas) { - LabelButton::OnPaint(canvas); - - if (!UseMd() || !HasFocus()) - return; - - cc::PaintFlags focus_flags; - focus_flags.setAntiAlias(true); - focus_flags.setColor( - SkColorSetA(GetNativeTheme()->GetSystemColor( - ui::NativeTheme::kColorId_FocusedBorderColor), - 0x66)); - focus_flags.setStyle(cc::PaintFlags::kStroke_Style); - focus_flags.setStrokeWidth(2); - PaintFocusRing(canvas, focus_flags); -} - void Checkbox::OnFocus() { LabelButton::OnFocus(); if (!UseMd()) @@ -181,6 +164,21 @@ ui::NativeTheme::kColorId_ButtonEnabledColor); } +void Checkbox::PaintButtonContents(gfx::Canvas* canvas) { + if (!UseMd() || !HasFocus()) + return; + + cc::PaintFlags focus_flags; + focus_flags.setAntiAlias(true); + focus_flags.setColor( + SkColorSetA(GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_FocusedBorderColor), + 0x66)); + focus_flags.setStyle(cc::PaintFlags::kStroke_Style); + focus_flags.setStrokeWidth(2); + PaintFocusRing(canvas, focus_flags); +} + gfx::ImageSkia Checkbox::GetImage(ButtonState for_state) const { if (UseMd()) { return gfx::CreateVectorIcon(
diff --git a/ui/views/controls/button/checkbox.h b/ui/views/controls/button/checkbox.h index e45ea53a..54ea6169 100644 --- a/ui/views/controls/button/checkbox.h +++ b/ui/views/controls/button/checkbox.h
@@ -43,13 +43,13 @@ // LabelButton: const char* GetClassName() const override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override; - void OnPaint(gfx::Canvas* canvas) override; void OnFocus() override; void OnBlur() override; void OnNativeThemeChanged(const ui::NativeTheme* theme) override; std::unique_ptr<InkDrop> CreateInkDrop() override; std::unique_ptr<InkDropRipple> CreateInkDropRipple() const override; SkColor GetInkDropBaseColor() const override; + void PaintButtonContents(gfx::Canvas* canvas) override; gfx::ImageSkia GetImage(ButtonState for_state) const override; // Set the image shown for each button state depending on whether it is
diff --git a/ui/views/controls/button/custom_button.cc b/ui/views/controls/button/custom_button.cc index 53809ab..2c69362 100644 --- a/ui/views/controls/button/custom_button.cc +++ b/ui/views/controls/button/custom_button.cc
@@ -20,6 +20,7 @@ #include "ui/views/controls/button/menu_button.h" #include "ui/views/controls/button/radio_button.h" #include "ui/views/controls/button/toggle_button.h" +#include "ui/views/painter.h" #include "ui/views/style/platform_style.h" #include "ui/views/widget/widget.h" @@ -136,6 +137,10 @@ return state_ == STATE_HOVERED; } +void CustomButton::SetFocusPainter(std::unique_ptr<Painter> focus_painter) { + focus_painter_ = std::move(focus_painter); +} + //////////////////////////////////////////////////////////////////////////////// // CustomButton, View overrides: @@ -352,6 +357,12 @@ AnimateInkDrop(InkDropState::HIDDEN, nullptr /* event */); } +void CustomButton::OnPaint(gfx::Canvas* canvas) { + Button::OnPaint(canvas); + PaintButtonContents(canvas); + Painter::PaintFocusPainter(this, canvas, focus_painter_.get()); +} + void CustomButton::GetAccessibleNodeData(ui::AXNodeData* node_data) { Button::GetAccessibleNodeData(node_data); switch (state_) { @@ -408,6 +419,12 @@ SetState(STATE_NORMAL); } +void CustomButton::OnFocus() { + Button::OnFocus(); + if (focus_painter_) + SchedulePaint(); +} + void CustomButton::OnBlur() { Button::OnBlur(); if (IsHotTracked() || state_ == STATE_PRESSED) { @@ -419,6 +436,8 @@ // it is possible for a Mouse Release to trigger an action however there // would be no visual cue to the user that this will occur. } + if (focus_painter_) + SchedulePaint(); } //////////////////////////////////////////////////////////////////////////////// @@ -455,6 +474,8 @@ return IsTriggerableEvent(event); } +void CustomButton::PaintButtonContents(gfx::Canvas* canvas) {} + bool CustomButton::ShouldEnterHoveredState() { if (!visible()) return false;
diff --git a/ui/views/controls/button/custom_button.h b/ui/views/controls/button/custom_button.h index b6f96710..b76b2f8 100644 --- a/ui/views/controls/button/custom_button.h +++ b/ui/views/controls/button/custom_button.h
@@ -17,6 +17,8 @@ namespace views { +class Painter; + // A button with custom rendering. The base of ImageButton and LabelButton. // Note that this type of button is not focusable by default and will not be // part of the focus chain, unless in accessibility mode. Call @@ -104,6 +106,8 @@ void SetHotTracked(bool is_hot_tracked); bool IsHotTracked() const; + void SetFocusPainter(std::unique_ptr<Painter> focus_painter); + // Overridden from View: void OnEnabledChanged() override; const char* GetClassName() const override; @@ -122,6 +126,9 @@ void ShowContextMenu(const gfx::Point& p, ui::MenuSourceType source_type) override; void OnDragDone() override; + // Instead of overriding this, subclasses that want custom painting should use + // PaintButtonContents. + void OnPaint(gfx::Canvas* canvas) final; void GetAccessibleNodeData(ui::AXNodeData* node_data) override; void VisibilityChanged(View* starting_from, bool is_visible) override; @@ -135,6 +142,7 @@ // Overridden from View: void ViewHierarchyChanged( const ViewHierarchyChangedDetails& details) override; + void OnFocus() override; void OnBlur() override; protected: @@ -162,6 +170,11 @@ // we simply return IsTriggerableEvent(event). virtual bool ShouldEnterPushedState(const ui::Event& event); + // Override to paint custom button contents. Any background or border set on + // the view will be painted before this is called and |focus_painter_| will be + // painted afterwards. + virtual void PaintButtonContents(gfx::Canvas* canvas); + // Returns true if the button should enter hovered state; that is, if the // mouse is over the button, and no other window has capture (which would // prevent the button from receiving MouseExited events and updating its @@ -177,6 +190,8 @@ } private: + FRIEND_TEST_ALL_PREFIXES(BlueButtonTest, Border); + ButtonState state_; gfx::ThrobAnimation hover_animation_; @@ -207,6 +222,8 @@ // The color of the ripple and hover. SkColor ink_drop_base_color_; + std::unique_ptr<Painter> focus_painter_; + DISALLOW_COPY_AND_ASSIGN(CustomButton); };
diff --git a/ui/views/controls/button/image_button.cc b/ui/views/controls/button/image_button.cc index abd2fab..19577bb 100644 --- a/ui/views/controls/button/image_button.cc +++ b/ui/views/controls/button/image_button.cc
@@ -32,8 +32,8 @@ : CustomButton(listener), h_alignment_(ALIGN_LEFT), v_alignment_(ALIGN_TOP), - draw_image_mirrored_(false), - focus_painter_(Painter::CreateDashedFocusPainter()) { + draw_image_mirrored_(false) { + SetFocusPainter(Painter::CreateDashedFocusPainter()); // By default, we request that the gfx::Canvas passed to our View::OnPaint() // implementation is flipped horizontally so that the button's images are // mirrored when the UI directionality is right-to-left. @@ -83,10 +83,6 @@ SchedulePaint(); } -void ImageButton::SetFocusPainter(std::unique_ptr<Painter> focus_painter) { - focus_painter_ = std::move(focus_painter); -} - void ImageButton::SetMinimumImageSize(const gfx::Size& size) { if (minimum_image_size_ == size) return; @@ -102,10 +98,21 @@ return kViewClassName; } -void ImageButton::OnPaint(gfx::Canvas* canvas) { - // Call the base class first to paint any background/borders. - View::OnPaint(canvas); +gfx::Size ImageButton::CalculatePreferredSize() const { + gfx::Size size(kDefaultWidth, kDefaultHeight); + if (!images_[STATE_NORMAL].isNull()) { + size = gfx::Size(images_[STATE_NORMAL].width(), + images_[STATE_NORMAL].height()); + } + size.SetToMax(minimum_image_size_); + + gfx::Insets insets = GetInsets(); + size.Enlarge(insets.width(), insets.height()); + return size; +} + +void ImageButton::PaintButtonContents(gfx::Canvas* canvas) { // TODO(estade|tdanderson|bruthig): The ink drop layer should be positioned // behind the button's image which means the image needs to be painted to its // own layer instead of to the Canvas. @@ -124,39 +131,11 @@ canvas->DrawImageInt(img, position.x(), position.y()); } - - Painter::PaintFocusPainter(this, canvas, focus_painter()); -} - -gfx::Size ImageButton::CalculatePreferredSize() const { - gfx::Size size(kDefaultWidth, kDefaultHeight); - if (!images_[STATE_NORMAL].isNull()) { - size = gfx::Size(images_[STATE_NORMAL].width(), - images_[STATE_NORMAL].height()); - } - - size.SetToMax(minimum_image_size_); - - gfx::Insets insets = GetInsets(); - size.Enlarge(insets.width(), insets.height()); - return size; } //////////////////////////////////////////////////////////////////////////////// // ImageButton, protected: -void ImageButton::OnFocus() { - CustomButton::OnFocus(); - if (focus_painter_.get()) - SchedulePaint(); -} - -void ImageButton::OnBlur() { - CustomButton::OnBlur(); - if (focus_painter_.get()) - SchedulePaint(); -} - gfx::ImageSkia ImageButton::GetImageToPaint() { gfx::ImageSkia img;
diff --git a/ui/views/controls/button/image_button.h b/ui/views/controls/button/image_button.h index 5ee902c..e17a5ce 100644 --- a/ui/views/controls/button/image_button.h +++ b/ui/views/controls/button/image_button.h
@@ -15,8 +15,6 @@ namespace views { -class Painter; - // An image button. // Note that this type of button is not focusable by default and will not be // part of the focus chain, unless in accessibility mode. Call @@ -60,8 +58,6 @@ void SetImageAlignment(HorizontalAlignment h_align, VerticalAlignment v_align); - void SetFocusPainter(std::unique_ptr<Painter> focus_painter); - // The minimum size of the contents (not including the border). The contents // will be at least this size, but may be larger if the image itself is // larger. @@ -75,13 +71,11 @@ // Overridden from View: const char* GetClassName() const override; - void OnPaint(gfx::Canvas* canvas) override; gfx::Size CalculatePreferredSize() const override; protected: - // Overridden from View: - void OnFocus() override; - void OnBlur() override; + // Overridden from CustomButton: + void PaintButtonContents(gfx::Canvas* canvas) override; // Returns the image to paint. This is invoked from paint and returns a value // from images. @@ -90,8 +84,6 @@ // Updates button background for |scale_factor|. void UpdateButtonBackground(ui::ScaleFactor scale_factor); - Painter* focus_painter() { return focus_painter_.get(); } - // The images used to render the different states of this button. gfx::ImageSkia images_[STATE_COUNT]; @@ -119,8 +111,6 @@ // resources. bool draw_image_mirrored_; - std::unique_ptr<Painter> focus_painter_; - DISALLOW_COPY_AND_ASSIGN(ImageButton); };
diff --git a/ui/views/controls/button/label_button.cc b/ui/views/controls/button/label_button.cc index ab726dc7..6fb6e39e 100644 --- a/ui/views/controls/button/label_button.cc +++ b/ui/views/controls/button/label_button.cc
@@ -179,10 +179,6 @@ InvalidateLayout(); } -void LabelButton::SetFocusPainter(std::unique_ptr<Painter> focus_painter) { - focus_painter_ = std::move(focus_painter); -} - gfx::Size LabelButton::CalculatePreferredSize() const { if (cached_preferred_size_valid_) return cached_preferred_size_; @@ -337,11 +333,6 @@ return !GetText().empty(); } -void LabelButton::OnPaint(gfx::Canvas* canvas) { - View::OnPaint(canvas); - Painter::PaintFocusPainter(this, canvas, focus_painter_.get()); -} - void LabelButton::OnFocus() { CustomButton::OnFocus(); // Typically the border renders differently when focused.
diff --git a/ui/views/controls/button/label_button.h b/ui/views/controls/button/label_button.h index a608594c..5d61e32c 100644 --- a/ui/views/controls/button/label_button.h +++ b/ui/views/controls/button/label_button.h
@@ -23,7 +23,6 @@ class InkDropContainerView; class LabelButtonBorder; -class Painter; // LabelButton is a button with text and an icon, it's not focusable by default. class VIEWS_EXPORT LabelButton : public CustomButton, @@ -89,9 +88,6 @@ // Call SetMinSize(gfx::Size()) to clear the size if needed. void SetImageLabelSpacing(int spacing); - void SetFocusPainter(std::unique_ptr<Painter> focus_painter); - Painter* focus_painter() { return focus_painter_.get(); } - // Creates the default border for this button. This can be overridden by // subclasses. virtual std::unique_ptr<LabelButtonBorder> CreateDefaultBorder() const; @@ -129,7 +125,6 @@ virtual bool ShouldUseFloodFillInkDrop() const; // View: - void OnPaint(gfx::Canvas* canvas) override; void OnFocus() override; void OnBlur() override; void OnNativeThemeChanged(const ui::NativeTheme* theme) override; @@ -239,8 +234,6 @@ // UI direction). gfx::HorizontalAlignment horizontal_alignment_; - std::unique_ptr<Painter> focus_painter_; - DISALLOW_COPY_AND_ASSIGN(LabelButton); };
diff --git a/ui/views/controls/button/menu_button.cc b/ui/views/controls/button/menu_button.cc index 74188e4..83ad60f3 100644 --- a/ui/views/controls/button/menu_button.cc +++ b/ui/views/controls/button/menu_button.cc
@@ -178,13 +178,6 @@ return event.type() == ui::ET_GESTURE_TAP; } -void MenuButton::OnPaint(gfx::Canvas* canvas) { - LabelButton::OnPaint(canvas); - - if (show_menu_marker_) - PaintMenuMarker(canvas); -} - //////////////////////////////////////////////////////////////////////////////// // // MenuButton - Events @@ -367,6 +360,11 @@ Activate(&event); } +void MenuButton::PaintButtonContents(gfx::Canvas* canvas) { + if (show_menu_marker_) + PaintMenuMarker(canvas); +} + void MenuButton::IncrementPressedLocked(bool snap_ink_drop_to_activated, const ui::LocatedEvent* event) { ++pressed_lock_count_;
diff --git a/ui/views/controls/button/menu_button.h b/ui/views/controls/button/menu_button.h index 0d4af71..9adbee93 100644 --- a/ui/views/controls/button/menu_button.h +++ b/ui/views/controls/button/menu_button.h
@@ -78,7 +78,6 @@ // Overridden from View: gfx::Size CalculatePreferredSize() const override; const char* GetClassName() const override; - void OnPaint(gfx::Canvas* canvas) override; bool OnMousePressed(const ui::MouseEvent& event) override; void OnMouseReleased(const ui::MouseEvent& event) override; void OnMouseEntered(const ui::MouseEvent& event) override; @@ -101,6 +100,7 @@ bool ShouldEnterPushedState(const ui::Event& event) override; void StateChanged(ButtonState old_state) override; void NotifyClick(const ui::Event& event) override; + void PaintButtonContents(gfx::Canvas* canvas) override; // Offset of the associated menu position. gfx::Point menu_offset_;
diff --git a/ui/views/controls/button/toggle_button.cc b/ui/views/controls/button/toggle_button.cc index f5885b1..5585524 100644 --- a/ui/views/controls/button/toggle_button.cc +++ b/ui/views/controls/button/toggle_button.cc
@@ -143,10 +143,6 @@ } } -void ToggleButton::SetFocusPainter(std::unique_ptr<Painter> focus_painter) { - focus_painter_ = std::move(focus_painter); -} - gfx::Size ToggleButton::CalculatePreferredSize() const { gfx::Rect rect(kTrackWidth, kTrackHeight); rect.Inset(gfx::Insets(-kTrackVerticalMargin, -kTrackHorizontalMargin)); @@ -189,38 +185,6 @@ return kViewClassName; } -void ToggleButton::OnPaint(gfx::Canvas* canvas) { - // Paint the toggle track. To look sharp even at fractional scale factors, - // round up to pixel boundaries. - canvas->Save(); - float dsf = canvas->UndoDeviceScaleFactor(); - gfx::RectF track_rect(GetTrackBounds()); - track_rect.Scale(dsf); - track_rect = gfx::RectF(gfx::ToEnclosingRect(track_rect)); - cc::PaintFlags track_flags; - track_flags.setAntiAlias(true); - const double color_ratio = slide_animation_.GetCurrentValue(); - track_flags.setColor(color_utils::AlphaBlend( - GetTrackColor(true), GetTrackColor(false), - static_cast<SkAlpha>(SK_AlphaOPAQUE * color_ratio))); - canvas->DrawRoundRect(track_rect, track_rect.height() / 2, track_flags); - canvas->Restore(); - - Painter::PaintFocusPainter(this, canvas, focus_painter_.get()); -} - -void ToggleButton::OnFocus() { - CustomButton::OnFocus(); - if (focus_painter_) - SchedulePaint(); -} - -void ToggleButton::OnBlur() { - CustomButton::OnBlur(); - if (focus_painter_) - SchedulePaint(); -} - void ToggleButton::OnBoundsChanged(const gfx::Rect& previous_bounds) { UpdateThumb(); } @@ -243,6 +207,24 @@ CustomButton::NotifyClick(event); } +void ToggleButton::PaintButtonContents(gfx::Canvas* canvas) { + // Paint the toggle track. To look sharp even at fractional scale factors, + // round up to pixel boundaries. + canvas->Save(); + float dsf = canvas->UndoDeviceScaleFactor(); + gfx::RectF track_rect(GetTrackBounds()); + track_rect.Scale(dsf); + track_rect = gfx::RectF(gfx::ToEnclosingRect(track_rect)); + cc::PaintFlags track_flags; + track_flags.setAntiAlias(true); + const double color_ratio = slide_animation_.GetCurrentValue(); + track_flags.setColor(color_utils::AlphaBlend( + GetTrackColor(true), GetTrackColor(false), + static_cast<SkAlpha>(SK_AlphaOPAQUE * color_ratio))); + canvas->DrawRoundRect(track_rect, track_rect.height() / 2, track_flags); + canvas->Restore(); +} + void ToggleButton::AddInkDropLayer(ui::Layer* ink_drop_layer) { thumb_view_->AddInkDropLayer(ink_drop_layer); }
diff --git a/ui/views/controls/button/toggle_button.h b/ui/views/controls/button/toggle_button.h index aef030a..7b35688 100644 --- a/ui/views/controls/button/toggle_button.h +++ b/ui/views/controls/button/toggle_button.h
@@ -10,8 +10,6 @@ namespace views { -class Painter; - // This view presents a button that has two states: on and off. This is similar // to a checkbox but has no text and looks more like a two-state horizontal // slider. @@ -25,8 +23,6 @@ void SetIsOn(bool is_on, bool animate); bool is_on() const { return is_on_; } - void SetFocusPainter(std::unique_ptr<Painter> focus_painter); - // views::View: gfx::Size CalculatePreferredSize() const override; @@ -47,15 +43,13 @@ // views::View: const char* GetClassName() const override; - void OnPaint(gfx::Canvas* canvas) override; - void OnFocus() override; - void OnBlur() override; void OnBoundsChanged(const gfx::Rect& previous_bounds) override; void OnNativeThemeChanged(const ui::NativeTheme* theme) override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override; // CustomButton: void NotifyClick(const ui::Event& event) override; + void PaintButtonContents(gfx::Canvas* canvas) override; void AddInkDropLayer(ui::Layer* ink_drop_layer) override; void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override; std::unique_ptr<InkDrop> CreateInkDrop() override; @@ -68,7 +62,6 @@ bool is_on_; gfx::SlideAnimation slide_animation_; ThumbView* thumb_view_; - std::unique_ptr<Painter> focus_painter_; DISALLOW_COPY_AND_ASSIGN(ToggleButton); };
diff --git a/ui/views/controls/scrollbar/scroll_bar_views.cc b/ui/views/controls/scrollbar/scroll_bar_views.cc index aec7b254..3dc0527 100644 --- a/ui/views/controls/scrollbar/scroll_bar_views.cc +++ b/ui/views/controls/scrollbar/scroll_bar_views.cc
@@ -35,7 +35,7 @@ const char* GetClassName() const override { return "ScrollBarButton"; } protected: - void OnPaint(gfx::Canvas* canvas) override; + void PaintButtonContents(gfx::Canvas* canvas) override; private: ui::NativeTheme::ExtraParams GetNativeThemeParams() const; @@ -80,7 +80,7 @@ GetNativeThemePart(), GetNativeThemeState(), GetNativeThemeParams()); } -void ScrollBarButton::OnPaint(gfx::Canvas* canvas) { +void ScrollBarButton::PaintButtonContents(gfx::Canvas* canvas) { gfx::Rect bounds(GetPreferredSize()); GetNativeTheme()->Paint(canvas->sk_canvas(), GetNativeThemePart(), GetNativeThemeState(), bounds,
diff --git a/ui/views/controls/webview/BUILD.gn b/ui/views/controls/webview/BUILD.gn index b8daeebab..2836c31 100644 --- a/ui/views/controls/webview/BUILD.gn +++ b/ui/views/controls/webview/BUILD.gn
@@ -8,6 +8,8 @@ "unhandled_keyboard_event_handler.h", "unhandled_keyboard_event_handler_mac.mm", "unhandled_keyboard_event_handler_win.cc", + "web_contents_set_background_color.cc", + "web_contents_set_background_color.h", "web_dialog_view.cc", "web_dialog_view.h", "webview.cc",
diff --git a/chrome/browser/chromeos/login/ui/web_contents_set_background_color.cc b/ui/views/controls/webview/web_contents_set_background_color.cc similarity index 85% rename from chrome/browser/chromeos/login/ui/web_contents_set_background_color.cc rename to ui/views/controls/webview/web_contents_set_background_color.cc index 6b57011..e5de0e42 100644 --- a/chrome/browser/chromeos/login/ui/web_contents_set_background_color.cc +++ b/ui/views/controls/webview/web_contents_set_background_color.cc
@@ -1,17 +1,17 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. +// Copyright 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/login/ui/web_contents_set_background_color.h" +#include "ui/views/controls/webview/web_contents_set_background_color.h" #include "base/memory/ptr_util.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host.h" #include "content/public/browser/render_widget_host_view.h" -DEFINE_WEB_CONTENTS_USER_DATA_KEY(chromeos::WebContentsSetBackgroundColor); +DEFINE_WEB_CONTENTS_USER_DATA_KEY(views::WebContentsSetBackgroundColor); -namespace chromeos { +namespace views { // static void WebContentsSetBackgroundColor::CreateForWebContentsWithColor( @@ -54,4 +54,4 @@ new_host->GetWidget()->GetView()->SetBackgroundColor(color_); } -} // namespace chromeos +} // namespace views
diff --git a/chrome/browser/chromeos/login/ui/web_contents_set_background_color.h b/ui/views/controls/webview/web_contents_set_background_color.h similarity index 72% rename from chrome/browser/chromeos/login/ui/web_contents_set_background_color.h rename to ui/views/controls/webview/web_contents_set_background_color.h index 024d310..e10a3a3 100644 --- a/chrome/browser/chromeos/login/ui/web_contents_set_background_color.h +++ b/ui/views/controls/webview/web_contents_set_background_color.h
@@ -2,16 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_UI_WEB_CONTENTS_SET_BACKGROUND_COLOR_H_ -#define CHROME_BROWSER_CHROMEOS_LOGIN_UI_WEB_CONTENTS_SET_BACKGROUND_COLOR_H_ +#ifndef UI_VIEWS_CONTROLS_WEBVIEW_WEB_CONTENTS_SET_BACKGROUND_COLOR_H_ +#define UI_VIEWS_CONTROLS_WEBVIEW_WEB_CONTENTS_SET_BACKGROUND_COLOR_H_ #include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_user_data.h" +#include "ui/views/controls/webview/webview_export.h" // Defined in SkColor.h (32-bit ARGB color). using SkColor = unsigned int; -namespace chromeos { +namespace views { // Ensures that the background color of a given WebContents instance is always // set to a given color value. @@ -19,8 +20,9 @@ : public content::WebContentsObserver, public content::WebContentsUserData<WebContentsSetBackgroundColor> { public: - static void CreateForWebContentsWithColor(content::WebContents* web_contents, - SkColor color); + WEBVIEW_EXPORT static void CreateForWebContentsWithColor( + content::WebContents* web_contents, + SkColor color); ~WebContentsSetBackgroundColor() override; @@ -39,6 +41,6 @@ DISALLOW_COPY_AND_ASSIGN(WebContentsSetBackgroundColor); }; -} // namespace chromeos +} // namespace views -#endif // CHROME_BROWSER_CHROMEOS_LOGIN_UI_WEB_CONTENTS_SET_BACKGROUND_COLOR_H_ +#endif // UI_VIEWS_CONTROLS_WEBVIEW_WEB_CONTENTS_SET_BACKGROUND_COLOR_H_
diff --git a/ui/webui/resources/js/cr/ui/array_data_model.js b/ui/webui/resources/js/cr/ui/array_data_model.js index 8efdb78..d5a596e 100644 --- a/ui/webui/resources/js/cr/ui/array_data_model.js +++ b/ui/webui/resources/js/cr/ui/array_data_model.js
@@ -126,7 +126,7 @@ slice: function(opt_from, opt_to) { var arr = this.array_; return this.indexes_.slice(opt_from, opt_to).map(function(index) { - return arr[index] + return arr[index]; }); }, @@ -399,7 +399,7 @@ } else { return function(a, b) { return defaultValuesCompareFunction.call(null, a[field], b[field]); - } + }; } },