From f360104beeb4fc363653280c9b6560e476572810 Mon Sep 17 00:00:00 2001 From: Heilig Benedek Date: Fri, 19 May 2017 21:35:13 +0200 Subject: [PATCH 1/8] add datalist element view --- atom/browser/api/atom_api_web_contents.cc | 35 ++ atom/browser/api/atom_api_web_contents.h | 11 + atom/browser/ui/autofill_popup.cc | 250 +++++++++++ atom/browser/ui/autofill_popup.h | 79 ++++ atom/browser/ui/views/autofill_popup_view.cc | 414 +++++++++++++++++++ atom/browser/ui/views/autofill_popup_view.h | 147 +++++++ atom/common/api/api_messages.h | 15 + atom/renderer/atom_autofill_agent.cc | 205 +++++++++ atom/renderer/atom_autofill_agent.h | 66 +++ atom/renderer/renderer_client_base.cc | 2 + filenames.gypi | 6 + 11 files changed, 1230 insertions(+) create mode 100644 atom/browser/ui/autofill_popup.cc create mode 100644 atom/browser/ui/autofill_popup.h create mode 100644 atom/browser/ui/views/autofill_popup_view.cc create mode 100644 atom/browser/ui/views/autofill_popup_view.h create mode 100644 atom/renderer/atom_autofill_agent.cc create mode 100644 atom/renderer/atom_autofill_agent.h diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index d47a4da2fec6..7e8e3508934d 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -17,6 +17,7 @@ #include "atom/browser/child_web_contents_tracker.h" #include "atom/browser/lib/bluetooth_chooser.h" #include "atom/browser/native_window.h" +#include "atom/browser/native_window_views.h" #include "atom/browser/net/atom_network_delegate.h" #include "atom/browser/osr/osr_output_device.h" #include "atom/browser/osr/osr_render_widget_host_view.h" @@ -83,6 +84,7 @@ #include "third_party/WebKit/public/web/WebFindOptions.h" #include "ui/display/screen.h" #include "ui/events/base_event_utils.h" +#include "ui/gfx/geometry/rect_f.h" #if !defined(OS_MACOSX) #include "ui/aura/window.h" @@ -441,6 +443,8 @@ void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate, registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING, content::Source(controller)); + autofill_popup_ = new AutofillPopup(web_contents->GetNativeView()); + Init(isolate); AttachAsUserData(web_contents); } @@ -740,6 +744,17 @@ void WebContents::RenderViewCreated(content::RenderViewHost* render_view_host) { impl->disable_hidden_ = !background_throttling_; } +void WebContents::RenderFrameCreated(content::RenderFrameHost* host) { + Send(new AtomAutofillViewHostMsg_RoutingId( + host->GetRoutingID(), routing_id())); +} + +void WebContents::RenderFrameHostChanged(content::RenderFrameHost* old_host, + content::RenderFrameHost* new_host) { + Send(new AtomAutofillViewHostMsg_RoutingId( + new_host->GetRoutingID(), routing_id())); +} + void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) { Emit("render-view-deleted", render_view_host->GetProcess()->GetID()); } @@ -976,6 +991,8 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) { OnGetZoomLevel) IPC_MESSAGE_HANDLER_CODE(ViewHostMsg_SetCursor, OnCursorChange, handled = false) + IPC_MESSAGE_HANDLER(AtomAutofillViewMsg_ShowPopup, OnShowAutofillPopup) + IPC_MESSAGE_HANDLER(AtomAutofillViewMsg_HidePopup, OnHideAutofillPopup) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -1608,6 +1625,24 @@ void WebContents::OnCursorChange(const content::WebCursor& cursor) { } } +void WebContents::OnShowAutofillPopup( + int routing_id, + const gfx::RectF& bounds, + const std::vector& values, + const std::vector& labels) { + auto relay = reinterpret_cast( + NativeWindow::FromWebContents(web_contents())); + autofill_popup_->CreateView( + routing_id, + web_contents(), + relay->widget(), + bounds); + autofill_popup_->SetItems(values, labels); +} +void WebContents::OnHideAutofillPopup() { + autofill_popup_->Hide(); +} + void WebContents::SetSize(const SetSizeParams& params) { if (guest_delegate_) guest_delegate_->SetSize(params); diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 6a04d6f518cf..f571d7358b61 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -12,6 +12,7 @@ #include "atom/browser/api/save_page_handler.h" #include "atom/browser/api/trackable_object.h" #include "atom/browser/common_web_contents_delegate.h" +#include "atom/browser/ui/autofill_popup.h" #include "content/common/cursors/webcursor.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" @@ -307,6 +308,9 @@ class WebContents : public mate::TrackableObject, // content::WebContentsObserver: void BeforeUnloadFired(const base::TimeTicks& proceed_time) override; void RenderViewCreated(content::RenderViewHost*) override; + void RenderFrameCreated(content::RenderFrameHost*) override; + void RenderFrameHostChanged(content::RenderFrameHost*, + content::RenderFrameHost*) override; void RenderViewDeleted(content::RenderViewHost*) override; void RenderProcessGone(base::TerminationStatus status) override; void DocumentLoadedInFrame( @@ -373,6 +377,12 @@ class WebContents : public mate::TrackableObject, // Called when we receive a CursorChange message from chromium. void OnCursorChange(const content::WebCursor& cursor); + + void OnShowAutofillPopup(int routing_id, + const gfx::RectF& bounds, + const std::vector& values, + const std::vector& labels); + void OnHideAutofillPopup(); // Called when received a message from renderer. void OnRendererMessage(const base::string16& channel, @@ -397,6 +407,7 @@ class WebContents : public mate::TrackableObject, std::unique_ptr dialog_manager_; std::unique_ptr guest_delegate_; + AutofillPopup* autofill_popup_; // The host webcontents that may contain this webcontents. WebContents* embedder_; diff --git a/atom/browser/ui/autofill_popup.cc b/atom/browser/ui/autofill_popup.cc new file mode 100644 index 000000000000..e775bf00c52d --- /dev/null +++ b/atom/browser/ui/autofill_popup.cc @@ -0,0 +1,250 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "atom/browser/ui/autofill_popup.h" +#include "atom/common/api/api_messages.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/gfx/text_utils.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/vector2d.h" + +namespace atom { + +namespace { + +std::pair CalculatePopupXAndWidth( + const display::Display& left_display, + const display::Display& right_display, + int popup_required_width, + const gfx::Rect& element_bounds, + bool is_rtl) { + int leftmost_display_x = left_display.bounds().x(); + int rightmost_display_x = + right_display.GetSizeInPixel().width() + right_display.bounds().x(); + + // Calculate the start coordinates for the popup if it is growing right or + // the end position if it is growing to the left, capped to screen space. + int right_growth_start = std::max( + leftmost_display_x, std::min(rightmost_display_x, element_bounds.x())); + int left_growth_end = + std::max(leftmost_display_x, + std::min(rightmost_display_x, element_bounds.right())); + + int right_available = rightmost_display_x - right_growth_start; + int left_available = left_growth_end - leftmost_display_x; + + int popup_width = + std::min(popup_required_width, std::max(right_available, left_available)); + + std::pair grow_right(right_growth_start, popup_width); + std::pair grow_left(left_growth_end - popup_width, popup_width); + + // Prefer to grow towards the end (right for LTR, left for RTL). But if there + // is not enough space available in the desired direction and more space in + // the other direction, reverse it. + if (is_rtl) { + return left_available >= popup_width || left_available >= right_available + ? grow_left + : grow_right; + } + return right_available >= popup_width || right_available >= left_available + ? grow_right + : grow_left; +} + +std::pair CalculatePopupYAndHeight( + const display::Display& top_display, + const display::Display& bottom_display, + int popup_required_height, + const gfx::Rect& element_bounds) { + int topmost_display_y = top_display.bounds().y(); + int bottommost_display_y = + bottom_display.GetSizeInPixel().height() + bottom_display.bounds().y(); + + // Calculate the start coordinates for the popup if it is growing down or + // the end position if it is growing up, capped to screen space. + int top_growth_end = std::max( + topmost_display_y, std::min(bottommost_display_y, element_bounds.y())); + int bottom_growth_start = + std::max(topmost_display_y, + std::min(bottommost_display_y, element_bounds.bottom())); + + int top_available = bottom_growth_start - topmost_display_y; + int bottom_available = bottommost_display_y - top_growth_end; + + // TODO(csharp): Restrict the popup height to what is available. + if (bottom_available >= popup_required_height || + bottom_available >= top_available) { + // The popup can appear below the field. + return std::make_pair(bottom_growth_start, popup_required_height); + } else { + // The popup must appear above the field. + return std::make_pair(top_growth_end - popup_required_height, + popup_required_height); + } +} + +display::Display GetDisplayNearestPoint( + const gfx::Point& point, + gfx::NativeView container_view) { + return display::Screen::GetScreen()->GetDisplayNearestPoint(point); +} + +} // namespace + +AutofillPopup::AutofillPopup(gfx::NativeView container_view) + : container_view_(container_view) { + bold_font_list_ = + gfx::FontList().DeriveWithWeight(gfx::Font::Weight::BOLD); + smaller_font_list_ = + gfx::FontList().DeriveWithSizeDelta(kSmallerFontSizeDelta); +} + +AutofillPopup::~AutofillPopup() { + Hide(); +} + +void AutofillPopup::CreateView( + int routing_id, + content::WebContents* web_contents, + views::Widget* parent_widget, + const gfx::RectF& r) { + web_contents_ = web_contents; + gfx::Rect lb(std::floor(r.x()), std::floor(r.y() + r.height()), + std::floor(r.width()), std::floor(r.height())); + gfx::Point menu_position(lb.origin()); + views::View::ConvertPointToScreen(parent_widget->GetContentsView(), &menu_position); + popup_bounds_ = gfx::Rect(menu_position, lb.size()); + element_bounds_ = popup_bounds_; + + view_.reset(new AutofillPopupView(this, parent_widget)); + view_->Show(); + + frame_routing_id_ = routing_id; +} + +void AutofillPopup::Hide() { + if (view_.get()) { + view_->Hide(); + view_.reset(); + } +} + +void AutofillPopup::SetItems(const std::vector& values, + const std::vector& labels) { + values_ = values; + labels_ = labels; + UpdatePopupBounds(); + if (view_.get()) { + view_->OnSuggestionsChanged(); + } +} + +void AutofillPopup::AcceptSuggestion(int index) { + web_contents_->Send(new AtomAutofillViewMsg_AcceptSuggestion( + frame_routing_id_, GetValueAt(index))); +} + +void AutofillPopup::UpdatePopupBounds() { + int desired_width = GetDesiredPopupWidth(); + int desired_height = GetDesiredPopupHeight(); + bool is_rtl = false; + + gfx::Point top_left_corner_of_popup = + element_bounds_.origin() + + gfx::Vector2d(element_bounds_.width() - desired_width, -desired_height); + + // This is the bottom right point of the popup if the popup is below the + // element and grows to the right (since the is the lowest and furthest right + // the popup could go). + gfx::Point bottom_right_corner_of_popup = + element_bounds_.origin() + + gfx::Vector2d(desired_width, element_bounds_.height() + desired_height); + + display::Display top_left_display = + GetDisplayNearestPoint(top_left_corner_of_popup, container_view_); + display::Display bottom_right_display = + GetDisplayNearestPoint(bottom_right_corner_of_popup, container_view_); + + std::pair popup_x_and_width = + CalculatePopupXAndWidth(top_left_display, bottom_right_display, + desired_width, element_bounds_, is_rtl); + std::pair popup_y_and_height = CalculatePopupYAndHeight( + top_left_display, bottom_right_display, desired_height, element_bounds_); + + popup_bounds_ = gfx::Rect(popup_x_and_width.first, popup_y_and_height.first, + popup_x_and_width.second, popup_y_and_height.second); +} + +int AutofillPopup::GetDesiredPopupHeight() { + return 2 * kPopupBorderThickness + values_.size() * kRowHeight; +} + +int AutofillPopup::GetDesiredPopupWidth() { + int popup_width = element_bounds_.width(); + + for (int i = 0; i < values_.size(); ++i) { + int row_size = kEndPadding + 2 * kPopupBorderThickness + + gfx::GetStringWidth(GetValueAt(i), GetValueFontListForRow(i)) + + gfx::GetStringWidth(GetLabelAt(i), GetLabelFontListForRow(i)); + if (GetLabelAt(i).length() > 0) + row_size += kNamePadding + kEndPadding; + + popup_width = std::max(popup_width, row_size); + } + + return popup_width; +} + +gfx::Rect AutofillPopup::GetRowBounds(int index) { + int top = kPopupBorderThickness + index * kRowHeight; + + return gfx::Rect(kPopupBorderThickness, top, + popup_bounds_.width() - 2 * kPopupBorderThickness, + kRowHeight); +} + +const gfx::FontList& AutofillPopup::GetValueFontListForRow(int index) const { + return bold_font_list_; +} + +const gfx::FontList& AutofillPopup::GetLabelFontListForRow(int index) const { + return smaller_font_list_; +} + +ui::NativeTheme::ColorId AutofillPopup::GetBackgroundColorIDForRow( + int index) const { + return index == view_->GetSelectedLine() + ? ui::NativeTheme::kColorId_ResultsTableHoveredBackground + : ui::NativeTheme::kColorId_ResultsTableNormalBackground; +} + +int AutofillPopup::GetLineCount() { + return values_.size(); +} + +base::string16 AutofillPopup::GetValueAt(int i) { + return values_.at(i); +} + +base::string16 AutofillPopup::GetLabelAt(int i) { + return labels_.at(i); +} + +int AutofillPopup::LineFromY(int y) const { + int current_height = kPopupBorderThickness; + + for (int i = 0; i < values_.size(); ++i) { + current_height += kRowHeight; + + if (y <= current_height) + return i; + } + + return values_.size() - 1; +} + +} // namespace atom \ No newline at end of file diff --git a/atom/browser/ui/autofill_popup.h b/atom/browser/ui/autofill_popup.h new file mode 100644 index 000000000000..fd3b8e93bdea --- /dev/null +++ b/atom/browser/ui/autofill_popup.h @@ -0,0 +1,79 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_UI_AUTOFILL_POPUP_H_ +#define ATOM_BROWSER_UI_AUTOFILL_POPUP_H_ + +#include "atom/browser/ui/views/autofill_popup_view.h" +#include "content/public/browser/web_contents.h" +#include "ui/gfx/font_list.h" +#include "ui/native_theme/native_theme.h" +#include "ui/views/widget/widget.h" + +namespace atom { + +class AutofillPopupView; + +class AutofillPopup { + public: + AutofillPopup(gfx::NativeView); + ~AutofillPopup(); + + void CreateView(int routing_id, content::WebContents* web_contents, + views::Widget* widget, const gfx::RectF& bounds); + void Hide(); + + void SetItems(const std::vector& values, + const std::vector& labels); + private: + friend class AutofillPopupView; + + void AcceptSuggestion(int index); + + void UpdatePopupBounds(); + int GetDesiredPopupHeight(); + int GetDesiredPopupWidth(); + gfx::Rect GetRowBounds(int i); + const gfx::FontList& GetValueFontListForRow(int index) const; + const gfx::FontList& GetLabelFontListForRow(int index) const; + ui::NativeTheme::ColorId GetBackgroundColorIDForRow(int index) const; + + int GetLineCount(); + base::string16 GetValueAt(int i); + base::string16 GetLabelAt(int i); + int LineFromY(int y) const; + + // The native view that contains this + gfx::NativeView container_view_; + + int selected_index_; + + // Popup location + gfx::Rect popup_bounds_; + + // Bounds of the autofilled element + gfx::Rect element_bounds_; + + // Datalist suggestions + std::vector values_; + std::vector labels_; + + // Font lists for the suggestions + gfx::FontList smaller_font_list_; + gfx::FontList bold_font_list_; + + // For sending the accepted suggestion to the render frame that + // asked to open the popup + int frame_routing_id_; + content::WebContents* web_contents_; + + // The popup view + std::unique_ptr view_; + + DISALLOW_COPY_AND_ASSIGN(AutofillPopup); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_UI_AUTOFILL_POPUP_H_ \ No newline at end of file diff --git a/atom/browser/ui/views/autofill_popup_view.cc b/atom/browser/ui/views/autofill_popup_view.cc new file mode 100644 index 000000000000..87a2d5995bd0 --- /dev/null +++ b/atom/browser/ui/views/autofill_popup_view.cc @@ -0,0 +1,414 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "atom/browser/ui/views/autofill_popup_view.h" +#include "base/bind.h" +#include "content/public/browser/render_view_host.h" +#include "ui/events/keycodes/keyboard_codes.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/text_utils.h" +#include "ui/views/border.h" +#include "ui/views/focus/focus_manager.h" +#include "ui/views/widget/widget.h" + +namespace atom { + +AutofillPopupView::AutofillPopupView( + AutofillPopup* popup, + views::Widget* parent_widget) + : popup_(popup), + parent_widget_(parent_widget), + weak_ptr_factory_(this) { + CreateChildViews(); + SetFocusBehavior(FocusBehavior::ALWAYS); + set_drag_controller(this); +} + +AutofillPopupView::~AutofillPopupView() { + if (popup_) { + auto host = popup_->web_contents_->GetRenderViewHost()->GetWidget(); + host->RemoveKeyPressEventCallback(keypress_callback_); + popup_ = nullptr; + } + + RemoveObserver(); + + if (GetWidget()) { + GetWidget()->Close(); + } +} + +void AutofillPopupView::Show() { + const bool initialize_widget = !GetWidget(); + if (initialize_widget) { + parent_widget_->AddObserver(this); + views::FocusManager* focus_manager = parent_widget_->GetFocusManager(); + focus_manager->RegisterAccelerator( + ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE), + ui::AcceleratorManager::kNormalPriority, + this); + focus_manager->RegisterAccelerator( + ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE), + ui::AcceleratorManager::kNormalPriority, + this); + + // The widget is destroyed by the corresponding NativeWidget, so we use + // a weak pointer to hold the reference and don't have to worry about + // deletion. + views::Widget* widget = new views::Widget; + views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); + params.delegate = this; + params.parent = parent_widget_->GetNativeView(); + widget->Init(params); + + // No animation for popup appearance (too distracting). + widget->SetVisibilityAnimationTransition(views::Widget::ANIMATE_HIDE); + + show_time_ = base::Time::Now(); + } + + SetBorder(views::CreateSolidBorder( + kPopupBorderThickness, + GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_UnfocusedBorderColor))); + + DoUpdateBoundsAndRedrawPopup(); + GetWidget()->Show(); + + if (initialize_widget) + views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this); + + keypress_callback_ = base::Bind(&AutofillPopupView::HandleKeyPressEvent, + base::Unretained(this)); + auto host = popup_->web_contents_->GetRenderViewHost()->GetWidget(); + host->AddKeyPressEventCallback(keypress_callback_); +} + +void AutofillPopupView::Hide() { + auto host = popup_->web_contents_->GetRenderViewHost()->GetWidget(); + host->RemoveKeyPressEventCallback(keypress_callback_); + popup_ = NULL; + + RemoveObserver(); + + if (GetWidget()) { + GetWidget()->Close(); + } else { + delete this; + } +} + +void AutofillPopupView::OnSuggestionsChanged() { + if (popup_->GetLineCount() == 0) { + popup_->Hide(); + return; + } + CreateChildViews(); + DoUpdateBoundsAndRedrawPopup(); +} + +void AutofillPopupView::OnSelectedRowChanged( + base::Optional previous_row_selection, + base::Optional current_row_selection) { + SchedulePaint(); + + if (current_row_selection) { + DCHECK_LT(*current_row_selection, child_count()); + child_at(*current_row_selection) + ->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true); + } +} + +void AutofillPopupView::DrawAutofillEntry(gfx::Canvas* canvas, + int index, + const gfx::Rect& entry_rect) { + canvas->FillRect( + entry_rect, + GetNativeTheme()->GetSystemColor( + popup_->GetBackgroundColorIDForRow(index))); + + const bool is_rtl = false; + const int text_align = + is_rtl ? gfx::Canvas::TEXT_ALIGN_RIGHT : gfx::Canvas::TEXT_ALIGN_LEFT; + gfx::Rect value_rect = entry_rect; + value_rect.Inset(kEndPadding, 0); + + int x_align_left = value_rect.x(); + const int value_width = gfx::GetStringWidth( + popup_->GetValueAt(index), + popup_->GetValueFontListForRow(index)); + int value_x_align_left = x_align_left; + value_x_align_left = + is_rtl ? value_rect.right() - value_width : value_rect.x(); + + canvas->DrawStringRectWithFlags( + popup_->GetValueAt(index), + popup_->GetValueFontListForRow(index), + GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_ResultsTableNormalText), + gfx::Rect(value_x_align_left, value_rect.y(), value_width, + value_rect.height()), + text_align); + + // Draw the label text, if one exists. + if (!popup_->GetLabelAt(index).empty()) { + const int label_width = gfx::GetStringWidth( + popup_->GetLabelAt(index), + popup_->GetLabelFontListForRow(index)); + int label_x_align_left = x_align_left; + label_x_align_left = + is_rtl ? value_rect.x() : value_rect.right() - label_width; + + canvas->DrawStringRectWithFlags( + popup_->GetLabelAt(index), + popup_->GetLabelFontListForRow(index), + GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_ResultsTableNormalDimmedText), + gfx::Rect(label_x_align_left, entry_rect.y(), label_width, + entry_rect.height()), + text_align); + } +} + +void AutofillPopupView::CreateChildViews() { + RemoveAllChildViews(true); + + for (int i = 0; i < popup_->GetLineCount(); ++i) { + auto child_view = new AutofillPopupChildView(popup_->GetValueAt(i)); + child_view->set_drag_controller(this); + AddChildView(child_view); + } +} + +void AutofillPopupView::DoUpdateBoundsAndRedrawPopup() { + GetWidget()->SetBounds(popup_->popup_bounds_); + SchedulePaint(); +} + +void AutofillPopupView::OnPaint(gfx::Canvas* canvas) { + if (!popup_) + return; + + canvas->DrawColor(GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_ResultsTableNormalBackground)); + OnPaintBorder(canvas); + + DCHECK_EQ(popup_->GetLineCount(), child_count()); + for (int i = 0; i < popup_->GetLineCount(); ++i) { + gfx::Rect line_rect = popup_->GetRowBounds(i); + + DrawAutofillEntry(canvas, i, line_rect); + } +} + +void AutofillPopupView::GetAccessibleNodeData(ui::AXNodeData* node_data) { + node_data->role = ui::AX_ROLE_MENU; + node_data->SetName("Autofill Menu"); +} + +void AutofillPopupView::OnMouseCaptureLost() { + ClearSelection(); +} + +bool AutofillPopupView::OnMouseDragged(const ui::MouseEvent& event) { + if (HitTestPoint(event.location())) { + SetSelection(event.location()); + + // We must return true in order to get future OnMouseDragged and + // OnMouseReleased events. + return true; + } + + // If we move off of the popup, we lose the selection. + ClearSelection(); + return false; +} + +void AutofillPopupView::OnMouseExited(const ui::MouseEvent& event) { + // Pressing return causes the cursor to hide, which will generate an + // OnMouseExited event. Pressing return should activate the current selection + // via AcceleratorPressed, so we need to let that run first. + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&AutofillPopupView::ClearSelection, + weak_ptr_factory_.GetWeakPtr())); +} + +void AutofillPopupView::OnMouseMoved(const ui::MouseEvent& event) { + // A synthesized mouse move will be sent when the popup is first shown. + // Don't preview a suggestion if the mouse happens to be hovering there. +#if defined(OS_WIN) + if (base::Time::Now() - show_time_ <= base::TimeDelta::FromMilliseconds(50)) + return; +#else + if (event.flags() & ui::EF_IS_SYNTHESIZED) + return; +#endif + + if (HitTestPoint(event.location())) + SetSelection(event.location()); + else + ClearSelection(); +} + +bool AutofillPopupView::OnMousePressed(const ui::MouseEvent& event) { + return event.GetClickCount() == 1; +} + +void AutofillPopupView::OnMouseReleased(const ui::MouseEvent& event) { + // We only care about the left click. + if (event.IsOnlyLeftMouseButton() && HitTestPoint(event.location())) + AcceptSelection(event.location()); +} + +void AutofillPopupView::OnGestureEvent(ui::GestureEvent* event) { + switch (event->type()) { + case ui::ET_GESTURE_TAP_DOWN: + case ui::ET_GESTURE_SCROLL_BEGIN: + case ui::ET_GESTURE_SCROLL_UPDATE: + if (HitTestPoint(event->location())) + SetSelection(event->location()); + else + ClearSelection(); + break; + case ui::ET_GESTURE_TAP: + case ui::ET_GESTURE_SCROLL_END: + if (HitTestPoint(event->location())) + AcceptSelection(event->location()); + else + ClearSelection(); + break; + case ui::ET_GESTURE_TAP_CANCEL: + case ui::ET_SCROLL_FLING_START: + ClearSelection(); + break; + default: + return; + } + event->SetHandled(); +} + +bool AutofillPopupView::AcceleratorPressed( + const ui::Accelerator& accelerator) { + DCHECK_EQ(accelerator.modifiers(), ui::EF_NONE); + + if (accelerator.key_code() == ui::VKEY_ESCAPE) { + popup_->Hide(); + return true; + } + + if (accelerator.key_code() == ui::VKEY_RETURN) + return AcceptSelectedLine(); + + NOTREACHED(); + return false; +} + +bool AutofillPopupView::HandleKeyPressEvent( + const content::NativeWebKeyboardEvent& event) { + switch (event.windowsKeyCode) { + case ui::VKEY_UP: + SelectPreviousLine(); + return true; + case ui::VKEY_DOWN: + SelectNextLine(); + return true; + case ui::VKEY_PRIOR: // Page up. + SetSelectedLine(0); + return true; + case ui::VKEY_NEXT: // Page down. + SetSelectedLine(popup_->GetLineCount() - 1); + return true; + case ui::VKEY_ESCAPE: + popup_->Hide(); + return true; + case ui::VKEY_TAB: + // A tab press should cause the selected line to be accepted, but still + // return false so the tab key press propagates and changes the cursor + // location. + AcceptSelectedLine(); + return false; + case ui::VKEY_RETURN: + return AcceptSelectedLine(); + default: + return false; + } +} + +void AutofillPopupView::OnNativeFocusChanged(gfx::NativeView focused_now) { + if (GetWidget() && GetWidget()->GetNativeView() != focused_now) + popup_->Hide(); +} + +void AutofillPopupView::OnWidgetBoundsChanged(views::Widget* widget, + const gfx::Rect& new_bounds) { + DCHECK_EQ(widget, parent_widget_); + popup_->Hide(); +} + +void AutofillPopupView::AcceptSuggestion(int index) { + popup_->AcceptSuggestion(index); + popup_->Hide(); +} + +bool AutofillPopupView::AcceptSelectedLine() { + if (!selected_line_) + return false; + + DCHECK_LT(*selected_line_, popup_->GetLineCount()); + + AcceptSuggestion(*selected_line_); + return true; +} + +void AutofillPopupView::AcceptSelection(const gfx::Point& point) { + SetSelectedLine(popup_->LineFromY(point.y())); + AcceptSelectedLine(); +} + +void AutofillPopupView::SetSelectedLine(base::Optional selected_line) { + if (selected_line_ == selected_line) + return; + + if (selected_line) { + DCHECK_LT(*selected_line, popup_->GetLineCount()); + } + + auto previous_selected_line(selected_line_); + selected_line_ = selected_line; + OnSelectedRowChanged(previous_selected_line, selected_line_); +} + +void AutofillPopupView::SetSelection(const gfx::Point& point) { + SetSelectedLine(popup_->LineFromY(point.y())); +} + +void AutofillPopupView::SelectNextLine() { + int new_selected_line = selected_line_ ? *selected_line_ + 1 : 0; + if (new_selected_line >= popup_->GetLineCount()) + new_selected_line = 0; + + SetSelectedLine(new_selected_line); +} + +void AutofillPopupView::SelectPreviousLine() { + int new_selected_line = selected_line_.value_or(0) - 1; + if (new_selected_line < 0) + new_selected_line = popup_->GetLineCount() - 1; + + SetSelectedLine(new_selected_line); +} + +void AutofillPopupView::ClearSelection() { + SetSelectedLine(base::nullopt); +} + +void AutofillPopupView::RemoveObserver() { + parent_widget_->GetFocusManager()->UnregisterAccelerators(this); + parent_widget_->RemoveObserver(this); + views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this); +} + +} // namespace atom \ No newline at end of file diff --git a/atom/browser/ui/views/autofill_popup_view.h b/atom/browser/ui/views/autofill_popup_view.h new file mode 100644 index 000000000000..5b29fe88a4d3 --- /dev/null +++ b/atom/browser/ui/views/autofill_popup_view.h @@ -0,0 +1,147 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_UI_VIEWS_AUTOFILL_POPUP_VIEW_H_ +#define ATOM_BROWSER_UI_VIEWS_AUTOFILL_POPUP_VIEW_H_ + +#include "atom/browser/ui/autofill_popup.h" + +#include "base/optional.h" +#include "content/public/browser/native_web_keyboard_event.h" +#include "content/public/browser/render_widget_host.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/views/drag_controller.h" +#include "ui/views/focus/widget_focus_manager.h" +#include "ui/views/widget/widget_delegate.h" +#include "ui/views/widget/widget_observer.h" + +namespace atom { + +const int kPopupBorderThickness = 1; +const int kSmallerFontSizeDelta = -1; +const int kEndPadding = 8; +const int kNamePadding = 15; +const int kRowHeight = 24; + +class AutofillPopup; + +// Child view only for triggering accessibility events. Rendering is handled +// by |AutofillPopupViewViews|. +class AutofillPopupChildView : public views::View { + public: + explicit AutofillPopupChildView(const base::string16& suggestion) + : suggestion_(suggestion) { + SetFocusBehavior(FocusBehavior::ALWAYS); + } + + private: + ~AutofillPopupChildView() override {} + + // views::Views implementation + void GetAccessibleNodeData(ui::AXNodeData* node_data) override { + node_data->role = ui::AX_ROLE_MENU_ITEM; + node_data->SetName(suggestion_); + } + + base::string16 suggestion_; + + DISALLOW_COPY_AND_ASSIGN(AutofillPopupChildView); +}; + +class AutofillPopupView : public views::WidgetDelegateView, + public views::WidgetFocusChangeListener, + public views::WidgetObserver, + public views::DragController { + public: + explicit AutofillPopupView(AutofillPopup* popup, + views::Widget* parent_widget); + ~AutofillPopupView() override; + + void Show(); + void Hide(); + + void OnSuggestionsChanged(); + + int GetSelectedLine() { return selected_line_.value_or(-1); } + + void WriteDragDataForView( + views::View*, const gfx::Point&, ui::OSExchangeData*) override {} + int GetDragOperationsForView(views::View*, const gfx::Point&) override { + return ui::DragDropTypes::DRAG_NONE; + } + bool CanStartDragForView( + views::View*, const gfx::Point&, const gfx::Point&) override { + return false; + } + + private: + void OnSelectedRowChanged(base::Optional previous_row_selection, + base::Optional current_row_selection); + + // Draw the given autofill entry in |entry_rect|. + void DrawAutofillEntry(gfx::Canvas* canvas, + int index, + const gfx::Rect& entry_rect); + + // Creates child views based on the suggestions given by |controller_|. These + // child views are used for accessibility events only. We need child views to + // populate the correct |AXNodeData| when user selects a suggestion. + void CreateChildViews(); + + void DoUpdateBoundsAndRedrawPopup(); + + // views::Views implementation. + void OnPaint(gfx::Canvas* canvas) override; + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + void OnMouseCaptureLost() override; + bool OnMouseDragged(const ui::MouseEvent& event) override; + void OnMouseExited(const ui::MouseEvent& event) override; + void OnMouseMoved(const ui::MouseEvent& event) override; + bool OnMousePressed(const ui::MouseEvent& event) override; + void OnMouseReleased(const ui::MouseEvent& event) override; + void OnGestureEvent(ui::GestureEvent* event) override; + bool AcceleratorPressed(const ui::Accelerator& accelerator) override; + bool HandleKeyPressEvent(const content::NativeWebKeyboardEvent& event); + + // views::WidgetFocusChangeListener implementation. + void OnNativeFocusChanged(gfx::NativeView focused_now) override; + + // views::WidgetObserver implementation. + void OnWidgetBoundsChanged(views::Widget* widget, + const gfx::Rect& new_bounds) override; + + void AcceptSuggestion(int index); + bool AcceptSelectedLine(); + void AcceptSelection(const gfx::Point& point); + void SetSelectedLine(base::Optional selected_line); + void SetSelection(const gfx::Point& point); + void SelectNextLine(); + void SelectPreviousLine(); + void ClearSelection(); + + // Stop observing the widget. + void RemoveObserver(); + + // Controller for this popup. Weak reference. + AutofillPopup* popup_; + + // The widget of the window that triggered this popup. Weak reference. + views::Widget* parent_widget_; + + // The time when the popup was shown. + base::Time show_time_; + + // The index of the currently selected line + base::Optional selected_line_; + + // The registered keypress callback, responsible for switching lines on + // key presses + content::RenderWidgetHost::KeyPressEventCallback keypress_callback_; + + base::WeakPtrFactory weak_ptr_factory_; +}; + +} // namespace atom + +#endif // ATOM_BROWSER_UI_VIEWS_AUTOFILL_POPUP_VIEW_H_ \ No newline at end of file diff --git a/atom/common/api/api_messages.h b/atom/common/api/api_messages.h index e25089b869a9..accd2eba0f79 100644 --- a/atom/common/api/api_messages.h +++ b/atom/common/api/api_messages.h @@ -9,6 +9,7 @@ #include "base/values.h" #include "content/public/common/common_param_traits.h" #include "ipc/ipc_message_macros.h" +#include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/ipc/gfx_param_traits.h" // The message starter should be declared in ipc/ipc_message_start.h. Since @@ -37,6 +38,20 @@ IPC_MESSAGE_ROUTED3(AtomViewMsg_Message, IPC_MESSAGE_ROUTED0(AtomViewMsg_Offscreen) +IPC_MESSAGE_ROUTED4(AtomAutofillViewMsg_ShowPopup, + int /* routing_id */, + gfx::RectF /* bounds */, + std::vector /* values */, + std::vector /* labels */) + +IPC_MESSAGE_ROUTED0(AtomAutofillViewMsg_HidePopup) + +IPC_MESSAGE_ROUTED1(AtomAutofillViewMsg_AcceptSuggestion, + base::string16 /* suggestion */) + +IPC_MESSAGE_ROUTED1(AtomAutofillViewHostMsg_RoutingId, + int /* id */) + // Sent by the renderer when the draggable regions are updated. IPC_MESSAGE_ROUTED1(AtomViewHostMsg_UpdateDraggableRegions, std::vector /* regions */) diff --git a/atom/renderer/atom_autofill_agent.cc b/atom/renderer/atom_autofill_agent.cc new file mode 100644 index 000000000000..34446a61b144 --- /dev/null +++ b/atom/renderer/atom_autofill_agent.cc @@ -0,0 +1,205 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/renderer/atom_autofill_agent.h" + +#include "atom/common/api/api_messages.h" +#include "content/public/renderer/render_frame.h" +#include "content/public/renderer/render_view.h" +#include "third_party/WebKit/public/platform/WebKeyboardEvent.h" +#include "third_party/WebKit/public/platform/WebString.h" +#include "third_party/WebKit/public/web/WebDocument.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" +#include "third_party/WebKit/public/web/WebOptionElement.h" +#include "third_party/WebKit/public/web/WebUserGestureIndicator.h" +#include "ui/events/keycodes/keyboard_codes.h" +#include "ui/gfx/geometry/rect_f.h" + +namespace atom { + +namespace { +const size_t kMaxDataLength = 1024; +const size_t kMaxListSize = 512; + +void GetDataListSuggestions(const blink::WebInputElement& element, + std::vector* values, + std::vector* labels) { + for (const auto& option : element.filteredDataListOptions()) { + values->push_back(option.value().utf16()); + if (option.value() != option.label()) + labels->push_back(option.label().utf16()); + else + labels->push_back(base::string16()); + } +} + +void TrimStringVectorForIPC(std::vector* strings) { + // Limit the size of the vector. + if (strings->size() > kMaxListSize) + strings->resize(kMaxListSize); + + // Limit the size of the strings in the vector. + for (size_t i = 0; i < strings->size(); ++i) { + if ((*strings)[i].length() > kMaxDataLength) + (*strings)[i].resize(kMaxDataLength); + } +} +} // namespace + +AutofillAgent::AutofillAgent( + content::RenderFrame* frame) + : content::RenderFrameObserver(frame), + render_frame_(frame), + weak_ptr_factory_(this) { + render_frame_->GetWebFrame()->setAutofillClient(this); +} + +void AutofillAgent::OnDestruct() { + delete this; +} + +void AutofillAgent::DidChangeScrollOffset() { + HidePopup(); +} + +void AutofillAgent::FocusedNodeChanged(const blink::WebNode&) { + HidePopup(); +} + +void AutofillAgent::textFieldDidEndEditing( + const blink::WebInputElement&) { + HidePopup(); +} + +void AutofillAgent::textFieldDidChange( + const blink::WebFormControlElement& element) { + if (!IsUserGesture() && !render_frame()->IsPasting()) + return; + + weak_ptr_factory_.InvalidateWeakPtrs(); + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&AutofillAgent::textFieldDidChangeImpl, + weak_ptr_factory_.GetWeakPtr(), element)); +} + +void AutofillAgent::textFieldDidChangeImpl( + const blink::WebFormControlElement& element) { + ShowSuggestionsOptions options; + options.requires_caret_at_end = true; + ShowSuggestions(element, options); +} + +void AutofillAgent::textFieldDidReceiveKeyDown( + const blink::WebInputElement& element, + const blink::WebKeyboardEvent& event) { + if (event.windowsKeyCode == ui::VKEY_DOWN || + event.windowsKeyCode == ui::VKEY_UP) { + ShowSuggestionsOptions options; + options.autofill_on_empty_values = true; + options.requires_caret_at_end = true; + ShowSuggestions(element, options); + } +} + +void AutofillAgent::openTextDataListChooser( + const blink::WebInputElement& element) { + ShowSuggestionsOptions options; + options.autofill_on_empty_values = true; + ShowSuggestions(element, options); +} + +void AutofillAgent::dataListOptionsChanged( + const blink::WebInputElement& element) { + if (!element.focused()) + return; + + ShowSuggestionsOptions options; + options.requires_caret_at_end = true; + ShowSuggestions(element, options); +} + +AutofillAgent::ShowSuggestionsOptions::ShowSuggestionsOptions() + : autofill_on_empty_values(false), + requires_caret_at_end(false) { +} + +void AutofillAgent::ShowSuggestions( + const blink::WebFormControlElement& element, + const ShowSuggestionsOptions& options) { + if (!element.isEnabled() || element.isReadOnly()) + return; + if (!element.suggestedValue().isEmpty()) + return; + const blink::WebInputElement* input_element = toWebInputElement(&element); + if (input_element) { + if (!input_element->isTextField()) + return; + } + + blink::WebString value = element.editingValue(); + if (value.length() > kMaxDataLength || + (!options.autofill_on_empty_values && value.isEmpty()) || + (options.requires_caret_at_end && + (element.selectionStart() != element.selectionEnd() || + element.selectionEnd() != static_cast(value.length())))) { + HidePopup(); + return; + } + + std::vector data_list_values; + std::vector data_list_labels; + if (input_element) { + GetDataListSuggestions( + *input_element, &data_list_values, &data_list_labels); + TrimStringVectorForIPC(&data_list_values); + TrimStringVectorForIPC(&data_list_labels); + } + + ShowPopup(element, data_list_values, data_list_labels); +} + +void AutofillAgent::OnAcceptSuggestion(base::string16 suggestion) { + auto element = render_frame_->GetWebFrame()->document().focusedElement(); + if (element.isFormControlElement()) { + toWebInputElement(&element)->setAutofillValue( + blink::WebString::fromUTF16(suggestion)); + } +} + +bool AutofillAgent::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(AutofillAgent, message) + IPC_MESSAGE_HANDLER(AtomAutofillViewHostMsg_RoutingId, + OnWebContentsRoutingIdReceived) + IPC_MESSAGE_HANDLER(AtomAutofillViewMsg_AcceptSuggestion, + OnAcceptSuggestion) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + + return handled; +} + +void AutofillAgent::OnWebContentsRoutingIdReceived(int id) { + web_contents_routing_id_ = id; +} + +bool AutofillAgent::IsUserGesture() const { + return blink::WebUserGestureIndicator::isProcessingUserGesture(); +} + +void AutofillAgent::HidePopup() { + Send(new AtomAutofillViewMsg_HidePopup(web_contents_routing_id_)); +} + +void AutofillAgent::ShowPopup( + const blink::WebFormControlElement& element, + const std::vector& values, + const std::vector& labels) { + gfx::RectF bounds = + render_frame_->GetRenderView()->ElementBoundsInWindow(element); + Send(new AtomAutofillViewMsg_ShowPopup( + web_contents_routing_id_, routing_id(), bounds, values, labels)); +} + +} // namespace atom \ No newline at end of file diff --git a/atom/renderer/atom_autofill_agent.h b/atom/renderer/atom_autofill_agent.h new file mode 100644 index 000000000000..122949577f14 --- /dev/null +++ b/atom/renderer/atom_autofill_agent.h @@ -0,0 +1,66 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_RENDERER_ATOM_AUTOFILL_AGENT_H_ +#define ATOM_RENDERER_ATOM_AUTOFILL_AGENT_H_ + +#include "base/memory/weak_ptr.h" +#include "content/public/renderer/render_frame_observer.h" +#include "third_party/WebKit/public/web/WebAutofillClient.h" +#include "third_party/WebKit/public/web/WebFormControlElement.h" +#include "third_party/WebKit/public/web/WebInputElement.h" +#include "third_party/WebKit/public/web/WebNode.h" + +namespace atom { + +class AutofillAgent : public content::RenderFrameObserver, + public blink::WebAutofillClient { + public: + AutofillAgent(content::RenderFrame* frame); + + // content::RenderFrameObserver: + void OnDestruct() override; + + void DidChangeScrollOffset() override; + void FocusedNodeChanged(const blink::WebNode&) override; + + private: + struct ShowSuggestionsOptions { + ShowSuggestionsOptions(); + bool autofill_on_empty_values; + bool requires_caret_at_end; + }; + + bool OnMessageReceived(const IPC::Message& message) override; + void OnWebContentsRoutingIdReceived(int); + + // blink::WebAutofillClient: + void textFieldDidEndEditing(const blink::WebInputElement&) override; + void textFieldDidChange(const blink::WebFormControlElement&) override; + void textFieldDidChangeImpl(const blink::WebFormControlElement&); + void textFieldDidReceiveKeyDown(const blink::WebInputElement&, + const blink::WebKeyboardEvent&) override; + void openTextDataListChooser(const blink::WebInputElement&) override; + void dataListOptionsChanged(const blink::WebInputElement&) override; + + bool IsUserGesture() const; + void HidePopup(); + void ShowPopup(const blink::WebFormControlElement&, + const std::vector&, + const std::vector&); + void ShowSuggestions(const blink::WebFormControlElement& element, + const ShowSuggestionsOptions& options); + void OnAcceptSuggestion(base::string16 suggestion); + + content::RenderFrame* render_frame_; + int web_contents_routing_id_; + + base::WeakPtrFactory weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(AutofillAgent); +}; + +} // namespace atom + +#endif // ATOM_RENDERER_ATOM_AUTOFILL_AGENT_H_ diff --git a/atom/renderer/renderer_client_base.cc b/atom/renderer/renderer_client_base.cc index 1219dfb5dcfa..c7818b2815f6 100644 --- a/atom/renderer/renderer_client_base.cc +++ b/atom/renderer/renderer_client_base.cc @@ -11,6 +11,7 @@ #include "atom/common/color_util.h" #include "atom/common/native_mate_converters/value_converter.h" #include "atom/common/options_switches.h" +#include "atom/renderer/atom_autofill_agent.h" #include "atom/renderer/atom_render_frame_observer.h" #include "atom/renderer/content_settings_observer.h" #include "atom/renderer/guest_view_container.h" @@ -120,6 +121,7 @@ void RendererClientBase::RenderThreadStarted() { void RendererClientBase::RenderFrameCreated( content::RenderFrame* render_frame) { new AtomRenderFrameObserver(render_frame, this); + new AutofillAgent(render_frame); new PepperHelper(render_frame); new ContentSettingsObserver(render_frame); new printing::PrintWebViewHelper(render_frame); diff --git a/filenames.gypi b/filenames.gypi index 63b46cb40e57..367c652ee675 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -291,6 +291,8 @@ 'atom/browser/ui/accelerator_util_views.cc', 'atom/browser/ui/atom_menu_model.cc', 'atom/browser/ui/atom_menu_model.h', + 'atom/browser/ui/autofill_popup.cc', + 'atom/browser/ui/autofill_popup.h', 'atom/browser/ui/certificate_trust.h', 'atom/browser/ui/certificate_trust_mac.mm', 'atom/browser/ui/certificate_trust_win.cc', @@ -318,6 +320,8 @@ 'atom/browser/ui/tray_icon_cocoa.mm', 'atom/browser/ui/tray_icon_observer.h', 'atom/browser/ui/tray_icon_win.cc', + 'atom/browser/ui/views/autofill_popup_view.cc', + 'atom/browser/ui/views/autofill_popup_view.h', 'atom/browser/ui/views/frameless_view.cc', 'atom/browser/ui/views/frameless_view.h', 'atom/browser/ui/views/global_menu_bar_x11.cc', @@ -479,6 +483,8 @@ 'atom/renderer/api/atom_api_spell_check_client.h', 'atom/renderer/api/atom_api_web_frame.cc', 'atom/renderer/api/atom_api_web_frame.h', + 'atom/renderer/atom_autofill_agent.cc', + 'atom/renderer/atom_autofill_agent.h', 'atom/renderer/atom_render_frame_observer.cc', 'atom/renderer/atom_render_frame_observer.h', 'atom/renderer/atom_render_view_observer.cc', From 4949531f57d961b56afd5b23f60eb2eaa6d5b172 Mon Sep 17 00:00:00 2001 From: Heilig Benedek Date: Fri, 19 May 2017 21:52:18 +0200 Subject: [PATCH 2/8] :art: lint fix --- atom/browser/api/atom_api_web_contents.cc | 8 ++--- atom/browser/api/atom_api_web_contents.h | 6 ++-- atom/browser/ui/autofill_popup.cc | 33 ++++++++++-------- atom/browser/ui/autofill_popup.h | 35 +++++++++++--------- atom/browser/ui/views/autofill_popup_view.cc | 18 +++++----- atom/browser/ui/views/autofill_popup_view.h | 22 ++++++------ atom/renderer/atom_autofill_agent.cc | 28 ++++++++-------- atom/renderer/atom_autofill_agent.h | 14 ++++---- 8 files changed, 88 insertions(+), 76 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 7e8e3508934d..eeec33caba49 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -749,7 +749,7 @@ void WebContents::RenderFrameCreated(content::RenderFrameHost* host) { host->GetRoutingID(), routing_id())); } -void WebContents::RenderFrameHostChanged(content::RenderFrameHost* old_host, +void WebContents::RenderFrameHostChanged(content::RenderFrameHost* old_host, content::RenderFrameHost* new_host) { Send(new AtomAutofillViewHostMsg_RoutingId( new_host->GetRoutingID(), routing_id())); @@ -1628,14 +1628,14 @@ void WebContents::OnCursorChange(const content::WebCursor& cursor) { void WebContents::OnShowAutofillPopup( int routing_id, const gfx::RectF& bounds, - const std::vector& values, - const std::vector& labels) { + const std::vector& values, + const std::vector& labels) { auto relay = reinterpret_cast( NativeWindow::FromWebContents(web_contents())); autofill_popup_->CreateView( routing_id, web_contents(), - relay->widget(), + relay->widget(), bounds); autofill_popup_->SetItems(values, labels); } diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index f571d7358b61..65741f9d0544 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -309,7 +309,7 @@ class WebContents : public mate::TrackableObject, void BeforeUnloadFired(const base::TimeTicks& proceed_time) override; void RenderViewCreated(content::RenderViewHost*) override; void RenderFrameCreated(content::RenderFrameHost*) override; - void RenderFrameHostChanged(content::RenderFrameHost*, + void RenderFrameHostChanged(content::RenderFrameHost*, content::RenderFrameHost*) override; void RenderViewDeleted(content::RenderViewHost*) override; void RenderProcessGone(base::TerminationStatus status) override; @@ -377,10 +377,10 @@ class WebContents : public mate::TrackableObject, // Called when we receive a CursorChange message from chromium. void OnCursorChange(const content::WebCursor& cursor); - + void OnShowAutofillPopup(int routing_id, const gfx::RectF& bounds, - const std::vector& values, + const std::vector& values, const std::vector& labels); void OnHideAutofillPopup(); diff --git a/atom/browser/ui/autofill_popup.cc b/atom/browser/ui/autofill_popup.cc index e775bf00c52d..e7234206d137 100644 --- a/atom/browser/ui/autofill_popup.cc +++ b/atom/browser/ui/autofill_popup.cc @@ -2,14 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include +#include +#include + #include "atom/browser/ui/autofill_popup.h" #include "atom/common/api/api_messages.h" #include "ui/display/display.h" #include "ui/display/screen.h" -#include "ui/gfx/text_utils.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/vector2d.h" +#include "ui/gfx/text_utils.h" namespace atom { @@ -97,9 +101,9 @@ display::Display GetDisplayNearestPoint( AutofillPopup::AutofillPopup(gfx::NativeView container_view) : container_view_(container_view) { - bold_font_list_ = + bold_font_list_ = gfx::FontList().DeriveWithWeight(gfx::Font::Weight::BOLD); - smaller_font_list_ = + smaller_font_list_ = gfx::FontList().DeriveWithSizeDelta(kSmallerFontSizeDelta); } @@ -110,19 +114,20 @@ AutofillPopup::~AutofillPopup() { void AutofillPopup::CreateView( int routing_id, content::WebContents* web_contents, - views::Widget* parent_widget, + views::Widget* parent_widget, const gfx::RectF& r) { web_contents_ = web_contents; - gfx::Rect lb(std::floor(r.x()), std::floor(r.y() + r.height()), + gfx::Rect lb(std::floor(r.x()), std::floor(r.y() + r.height()), std::floor(r.width()), std::floor(r.height())); gfx::Point menu_position(lb.origin()); - views::View::ConvertPointToScreen(parent_widget->GetContentsView(), &menu_position); + views::View::ConvertPointToScreen( + parent_widget->GetContentsView(), &menu_position); popup_bounds_ = gfx::Rect(menu_position, lb.size()); element_bounds_ = popup_bounds_; - + view_.reset(new AutofillPopupView(this, parent_widget)); view_->Show(); - + frame_routing_id_ = routing_id; } @@ -152,7 +157,7 @@ void AutofillPopup::UpdatePopupBounds() { int desired_width = GetDesiredPopupWidth(); int desired_height = GetDesiredPopupHeight(); bool is_rtl = false; - + gfx::Point top_left_corner_of_popup = element_bounds_.origin() + gfx::Vector2d(element_bounds_.width() - desired_width, -desired_height); @@ -187,10 +192,10 @@ int AutofillPopup::GetDesiredPopupWidth() { int popup_width = element_bounds_.width(); for (int i = 0; i < values_.size(); ++i) { - int row_size = kEndPadding + 2 * kPopupBorderThickness + - gfx::GetStringWidth(GetValueAt(i), GetValueFontListForRow(i)) + + int row_size = kEndPadding + 2 * kPopupBorderThickness + + gfx::GetStringWidth(GetValueAt(i), GetValueFontListForRow(i)) + gfx::GetStringWidth(GetLabelAt(i), GetLabelFontListForRow(i)); - if (GetLabelAt(i).length() > 0) + if (GetLabelAt(i).length() > 0) row_size += kNamePadding + kEndPadding; popup_width = std::max(popup_width, row_size); @@ -243,8 +248,8 @@ int AutofillPopup::LineFromY(int y) const { if (y <= current_height) return i; } - + return values_.size() - 1; } -} // namespace atom \ No newline at end of file +} // namespace atom diff --git a/atom/browser/ui/autofill_popup.h b/atom/browser/ui/autofill_popup.h index fd3b8e93bdea..ada50dbd9cfc 100644 --- a/atom/browser/ui/autofill_popup.h +++ b/atom/browser/ui/autofill_popup.h @@ -5,6 +5,8 @@ #ifndef ATOM_BROWSER_UI_AUTOFILL_POPUP_H_ #define ATOM_BROWSER_UI_AUTOFILL_POPUP_H_ +#include + #include "atom/browser/ui/views/autofill_popup_view.h" #include "content/public/browser/web_contents.h" #include "ui/gfx/font_list.h" @@ -14,23 +16,24 @@ namespace atom { class AutofillPopupView; - + class AutofillPopup { public: - AutofillPopup(gfx::NativeView); + explicit AutofillPopup(gfx::NativeView); ~AutofillPopup(); void CreateView(int routing_id, content::WebContents* web_contents, views::Widget* widget, const gfx::RectF& bounds); void Hide(); - + void SetItems(const std::vector& values, const std::vector& labels); + private: friend class AutofillPopupView; - + void AcceptSuggestion(int index); - + void UpdatePopupBounds(); int GetDesiredPopupHeight(); int GetDesiredPopupWidth(); @@ -38,36 +41,36 @@ class AutofillPopup { const gfx::FontList& GetValueFontListForRow(int index) const; const gfx::FontList& GetLabelFontListForRow(int index) const; ui::NativeTheme::ColorId GetBackgroundColorIDForRow(int index) const; - + int GetLineCount(); base::string16 GetValueAt(int i); base::string16 GetLabelAt(int i); int LineFromY(int y) const; - + // The native view that contains this gfx::NativeView container_view_; - + int selected_index_; - + // Popup location gfx::Rect popup_bounds_; - + // Bounds of the autofilled element gfx::Rect element_bounds_; - + // Datalist suggestions std::vector values_; std::vector labels_; - + // Font lists for the suggestions gfx::FontList smaller_font_list_; gfx::FontList bold_font_list_; - - // For sending the accepted suggestion to the render frame that + + // For sending the accepted suggestion to the render frame that // asked to open the popup int frame_routing_id_; content::WebContents* web_contents_; - + // The popup view std::unique_ptr view_; @@ -76,4 +79,4 @@ class AutofillPopup { } // namespace atom -#endif // ATOM_BROWSER_UI_AUTOFILL_POPUP_H_ \ No newline at end of file +#endif // ATOM_BROWSER_UI_AUTOFILL_POPUP_H_ diff --git a/atom/browser/ui/views/autofill_popup_view.cc b/atom/browser/ui/views/autofill_popup_view.cc index 87a2d5995bd0..070844872262 100644 --- a/atom/browser/ui/views/autofill_popup_view.cc +++ b/atom/browser/ui/views/autofill_popup_view.cc @@ -80,7 +80,7 @@ void AutofillPopupView::Show() { if (initialize_widget) views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this); - + keypress_callback_ = base::Bind(&AutofillPopupView::HandleKeyPressEvent, base::Unretained(this)); auto host = popup_->web_contents_->GetRenderViewHost()->GetWidget(); @@ -129,13 +129,13 @@ void AutofillPopupView::DrawAutofillEntry(gfx::Canvas* canvas, entry_rect, GetNativeTheme()->GetSystemColor( popup_->GetBackgroundColorIDForRow(index))); - + const bool is_rtl = false; const int text_align = is_rtl ? gfx::Canvas::TEXT_ALIGN_RIGHT : gfx::Canvas::TEXT_ALIGN_LEFT; gfx::Rect value_rect = entry_rect; value_rect.Inset(kEndPadding, 0); - + int x_align_left = value_rect.x(); const int value_width = gfx::GetStringWidth( popup_->GetValueAt(index), @@ -143,7 +143,7 @@ void AutofillPopupView::DrawAutofillEntry(gfx::Canvas* canvas, int value_x_align_left = x_align_left; value_x_align_left = is_rtl ? value_rect.right() - value_width : value_rect.x(); - + canvas->DrawStringRectWithFlags( popup_->GetValueAt(index), popup_->GetValueFontListForRow(index), @@ -159,7 +159,7 @@ void AutofillPopupView::DrawAutofillEntry(gfx::Canvas* canvas, popup_->GetLabelAt(index), popup_->GetLabelFontListForRow(index)); int label_x_align_left = x_align_left; - label_x_align_left = + label_x_align_left = is_rtl ? value_rect.x() : value_rect.right() - label_width; canvas->DrawStringRectWithFlags( @@ -191,15 +191,15 @@ void AutofillPopupView::DoUpdateBoundsAndRedrawPopup() { void AutofillPopupView::OnPaint(gfx::Canvas* canvas) { if (!popup_) return; - + canvas->DrawColor(GetNativeTheme()->GetSystemColor( ui::NativeTheme::kColorId_ResultsTableNormalBackground)); OnPaintBorder(canvas); - + DCHECK_EQ(popup_->GetLineCount(), child_count()); for (int i = 0; i < popup_->GetLineCount(); ++i) { gfx::Rect line_rect = popup_->GetRowBounds(i); - + DrawAutofillEntry(canvas, i, line_rect); } } @@ -411,4 +411,4 @@ void AutofillPopupView::RemoveObserver() { views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this); } -} // namespace atom \ No newline at end of file +} // namespace atom diff --git a/atom/browser/ui/views/autofill_popup_view.h b/atom/browser/ui/views/autofill_popup_view.h index 5b29fe88a4d3..392e64273df7 100644 --- a/atom/browser/ui/views/autofill_popup_view.h +++ b/atom/browser/ui/views/autofill_popup_view.h @@ -57,12 +57,12 @@ class AutofillPopupView : public views::WidgetDelegateView, explicit AutofillPopupView(AutofillPopup* popup, views::Widget* parent_widget); ~AutofillPopupView() override; - + void Show(); void Hide(); - + void OnSuggestionsChanged(); - + int GetSelectedLine() { return selected_line_.value_or(-1); } void WriteDragDataForView( @@ -71,8 +71,8 @@ class AutofillPopupView : public views::WidgetDelegateView, return ui::DragDropTypes::DRAG_NONE; } bool CanStartDragForView( - views::View*, const gfx::Point&, const gfx::Point&) override { - return false; + views::View*, const gfx::Point&, const gfx::Point&) override { + return false; } private: @@ -88,9 +88,9 @@ class AutofillPopupView : public views::WidgetDelegateView, // child views are used for accessibility events only. We need child views to // populate the correct |AXNodeData| when user selects a suggestion. void CreateChildViews(); - + void DoUpdateBoundsAndRedrawPopup(); - + // views::Views implementation. void OnPaint(gfx::Canvas* canvas) override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override; @@ -103,7 +103,7 @@ class AutofillPopupView : public views::WidgetDelegateView, void OnGestureEvent(ui::GestureEvent* event) override; bool AcceleratorPressed(const ui::Accelerator& accelerator) override; bool HandleKeyPressEvent(const content::NativeWebKeyboardEvent& event); - + // views::WidgetFocusChangeListener implementation. void OnNativeFocusChanged(gfx::NativeView focused_now) override; @@ -131,10 +131,10 @@ class AutofillPopupView : public views::WidgetDelegateView, // The time when the popup was shown. base::Time show_time_; - + // The index of the currently selected line base::Optional selected_line_; - + // The registered keypress callback, responsible for switching lines on // key presses content::RenderWidgetHost::KeyPressEventCallback keypress_callback_; @@ -144,4 +144,4 @@ class AutofillPopupView : public views::WidgetDelegateView, } // namespace atom -#endif // ATOM_BROWSER_UI_VIEWS_AUTOFILL_POPUP_VIEW_H_ \ No newline at end of file +#endif // ATOM_BROWSER_UI_VIEWS_AUTOFILL_POPUP_VIEW_H_ diff --git a/atom/renderer/atom_autofill_agent.cc b/atom/renderer/atom_autofill_agent.cc index 34446a61b144..739fb8fe4908 100644 --- a/atom/renderer/atom_autofill_agent.cc +++ b/atom/renderer/atom_autofill_agent.cc @@ -4,6 +4,8 @@ #include "atom/renderer/atom_autofill_agent.h" +#include + #include "atom/common/api/api_messages.h" #include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_view.h" @@ -17,11 +19,11 @@ #include "ui/gfx/geometry/rect_f.h" namespace atom { - + namespace { const size_t kMaxDataLength = 1024; const size_t kMaxListSize = 512; - + void GetDataListSuggestions(const blink::WebInputElement& element, std::vector* values, std::vector* labels) { @@ -45,7 +47,7 @@ void TrimStringVectorForIPC(std::vector* strings) { (*strings)[i].resize(kMaxDataLength); } } -} // namespace +} // namespace AutofillAgent::AutofillAgent( content::RenderFrame* frame) @@ -73,10 +75,10 @@ void AutofillAgent::textFieldDidEndEditing( } void AutofillAgent::textFieldDidChange( - const blink::WebFormControlElement& element) { + const blink::WebFormControlElement& element) { if (!IsUserGesture() && !render_frame()->IsPasting()) return; - + weak_ptr_factory_.InvalidateWeakPtrs(); base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&AutofillAgent::textFieldDidChangeImpl, @@ -84,14 +86,14 @@ void AutofillAgent::textFieldDidChange( } void AutofillAgent::textFieldDidChangeImpl( - const blink::WebFormControlElement& element) { + const blink::WebFormControlElement& element) { ShowSuggestionsOptions options; options.requires_caret_at_end = true; ShowSuggestions(element, options); } void AutofillAgent::textFieldDidReceiveKeyDown( - const blink::WebInputElement& element, + const blink::WebInputElement& element, const blink::WebKeyboardEvent& event) { if (event.windowsKeyCode == ui::VKEY_DOWN || event.windowsKeyCode == ui::VKEY_UP) { @@ -113,7 +115,7 @@ void AutofillAgent::dataListOptionsChanged( const blink::WebInputElement& element) { if (!element.focused()) return; - + ShowSuggestionsOptions options; options.requires_caret_at_end = true; ShowSuggestions(element, options); @@ -136,7 +138,7 @@ void AutofillAgent::ShowSuggestions( if (!input_element->isTextField()) return; } - + blink::WebString value = element.editingValue(); if (value.length() > kMaxDataLength || (!options.autofill_on_empty_values && value.isEmpty()) || @@ -146,7 +148,7 @@ void AutofillAgent::ShowSuggestions( HidePopup(); return; } - + std::vector data_list_values; std::vector data_list_labels; if (input_element) { @@ -155,7 +157,7 @@ void AutofillAgent::ShowSuggestions( TrimStringVectorForIPC(&data_list_values); TrimStringVectorForIPC(&data_list_labels); } - + ShowPopup(element, data_list_values, data_list_labels); } @@ -196,10 +198,10 @@ void AutofillAgent::ShowPopup( const blink::WebFormControlElement& element, const std::vector& values, const std::vector& labels) { - gfx::RectF bounds = + gfx::RectF bounds = render_frame_->GetRenderView()->ElementBoundsInWindow(element); Send(new AtomAutofillViewMsg_ShowPopup( web_contents_routing_id_, routing_id(), bounds, values, labels)); } -} // namespace atom \ No newline at end of file +} // namespace atom diff --git a/atom/renderer/atom_autofill_agent.h b/atom/renderer/atom_autofill_agent.h index 122949577f14..16ecb98bd7e5 100644 --- a/atom/renderer/atom_autofill_agent.h +++ b/atom/renderer/atom_autofill_agent.h @@ -5,6 +5,8 @@ #ifndef ATOM_RENDERER_ATOM_AUTOFILL_AGENT_H_ #define ATOM_RENDERER_ATOM_AUTOFILL_AGENT_H_ +#include + #include "base/memory/weak_ptr.h" #include "content/public/renderer/render_frame_observer.h" #include "third_party/WebKit/public/web/WebAutofillClient.h" @@ -14,14 +16,14 @@ namespace atom { -class AutofillAgent : public content::RenderFrameObserver, +class AutofillAgent : public content::RenderFrameObserver, public blink::WebAutofillClient { public: - AutofillAgent(content::RenderFrame* frame); + explicit AutofillAgent(content::RenderFrame* frame); // content::RenderFrameObserver: void OnDestruct() override; - + void DidChangeScrollOffset() override; void FocusedNodeChanged(const blink::WebNode&) override; @@ -31,9 +33,9 @@ class AutofillAgent : public content::RenderFrameObserver, bool autofill_on_empty_values; bool requires_caret_at_end; }; - + bool OnMessageReceived(const IPC::Message& message) override; - void OnWebContentsRoutingIdReceived(int); + void OnWebContentsRoutingIdReceived(int routing_id); // blink::WebAutofillClient: void textFieldDidEndEditing(const blink::WebInputElement&) override; @@ -43,7 +45,7 @@ class AutofillAgent : public content::RenderFrameObserver, const blink::WebKeyboardEvent&) override; void openTextDataListChooser(const blink::WebInputElement&) override; void dataListOptionsChanged(const blink::WebInputElement&) override; - + bool IsUserGesture() const; void HidePopup(); void ShowPopup(const blink::WebFormControlElement&, From a95d6b997b4bda627490ff0a8dbb0e322f7076d2 Mon Sep 17 00:00:00 2001 From: Heilig Benedek Date: Sat, 20 May 2017 04:21:11 +0200 Subject: [PATCH 3/8] add ability to open popup on second click --- atom/renderer/atom_autofill_agent.cc | 48 ++++++++++++++++++++++++---- atom/renderer/atom_autofill_agent.h | 29 +++++++++++++++++ 2 files changed, 71 insertions(+), 6 deletions(-) diff --git a/atom/renderer/atom_autofill_agent.cc b/atom/renderer/atom_autofill_agent.cc index 739fb8fe4908..4ebe6160b5ad 100644 --- a/atom/renderer/atom_autofill_agent.cc +++ b/atom/renderer/atom_autofill_agent.cc @@ -53,10 +53,17 @@ AutofillAgent::AutofillAgent( content::RenderFrame* frame) : content::RenderFrameObserver(frame), render_frame_(frame), + helper_(new Helper(this)), + focused_node_was_last_clicked_(false), + was_focused_before_now_(false), weak_ptr_factory_(this) { render_frame_->GetWebFrame()->setAutofillClient(this); } +AutofillAgent::~AutofillAgent() { + delete helper_; +} + void AutofillAgent::OnDestruct() { delete this; } @@ -66,6 +73,7 @@ void AutofillAgent::DidChangeScrollOffset() { } void AutofillAgent::FocusedNodeChanged(const blink::WebNode&) { + was_focused_before_now_ = false; HidePopup(); } @@ -161,12 +169,17 @@ void AutofillAgent::ShowSuggestions( ShowPopup(element, data_list_values, data_list_labels); } -void AutofillAgent::OnAcceptSuggestion(base::string16 suggestion) { - auto element = render_frame_->GetWebFrame()->document().focusedElement(); - if (element.isFormControlElement()) { - toWebInputElement(&element)->setAutofillValue( - blink::WebString::fromUTF16(suggestion)); - } +AutofillAgent::Helper::Helper(AutofillAgent* agent) + : content::RenderViewObserver(agent->render_frame_->GetRenderView()), + agent_(agent) { +} + +void AutofillAgent::Helper::OnMouseDown(const blink::WebNode& node) { + agent_->focused_node_was_last_clicked_ = !node.isNull() && node.focused(); +} + +void AutofillAgent::Helper::FocusChangeComplete() { + agent_->DoFocusChangeComplete(); } bool AutofillAgent::OnMessageReceived(const IPC::Message& message) { @@ -204,4 +217,27 @@ void AutofillAgent::ShowPopup( web_contents_routing_id_, routing_id(), bounds, values, labels)); } +void AutofillAgent::OnAcceptSuggestion(base::string16 suggestion) { + auto element = render_frame_->GetWebFrame()->document().focusedElement(); + if (element.isFormControlElement()) { + toWebInputElement(&element)->setAutofillValue( + blink::WebString::fromUTF16(suggestion)); + } +} + +void AutofillAgent::DoFocusChangeComplete() { + auto element = render_frame_->GetWebFrame()->document().focusedElement(); + if (element.isNull() || !element.isFormControlElement()) + return; + + if (focused_node_was_last_clicked_ && was_focused_before_now_) { + ShowSuggestionsOptions options; + options.autofill_on_empty_values = true; + ShowSuggestions(*toWebInputElement(&element), options); + } + + was_focused_before_now_ = true; + focused_node_was_last_clicked_ = false; +} + } // namespace atom diff --git a/atom/renderer/atom_autofill_agent.h b/atom/renderer/atom_autofill_agent.h index 16ecb98bd7e5..f06692a78fd0 100644 --- a/atom/renderer/atom_autofill_agent.h +++ b/atom/renderer/atom_autofill_agent.h @@ -9,6 +9,7 @@ #include "base/memory/weak_ptr.h" #include "content/public/renderer/render_frame_observer.h" +#include "content/public/renderer/render_view_observer.h" #include "third_party/WebKit/public/web/WebAutofillClient.h" #include "third_party/WebKit/public/web/WebFormControlElement.h" #include "third_party/WebKit/public/web/WebInputElement.h" @@ -20,6 +21,7 @@ class AutofillAgent : public content::RenderFrameObserver, public blink::WebAutofillClient { public: explicit AutofillAgent(content::RenderFrame* frame); + ~AutofillAgent(); // content::RenderFrameObserver: void OnDestruct() override; @@ -28,6 +30,21 @@ class AutofillAgent : public content::RenderFrameObserver, void FocusedNodeChanged(const blink::WebNode&) override; private: + + class Helper : public content::RenderViewObserver { + public: + Helper(AutofillAgent* agent); + + // content::RenderViewObserver implementation. + void OnDestruct() override {} + void OnMouseDown(const blink::WebNode&) override; + void FocusChangeComplete() override; + + private: + AutofillAgent* agent_; + }; + friend class Helper; + struct ShowSuggestionsOptions { ShowSuggestionsOptions(); bool autofill_on_empty_values; @@ -55,9 +72,21 @@ class AutofillAgent : public content::RenderFrameObserver, const ShowSuggestionsOptions& options); void OnAcceptSuggestion(base::string16 suggestion); + void DoFocusChangeComplete(); + content::RenderFrame* render_frame_; int web_contents_routing_id_; + Helper* helper_; + + // True when the last click was on the focused node. + bool focused_node_was_last_clicked_; + + // This is set to false when the focus changes, then set back to true soon + // afterwards. This helps track whether an event happened after a node was + // already focused, or if it caused the focus to change. + bool was_focused_before_now_; + base::WeakPtrFactory weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(AutofillAgent); From 218e28b136124bdad6abd7e763ba89b36910aaca Mon Sep 17 00:00:00 2001 From: Heilig Benedek Date: Sun, 21 May 2017 19:55:19 +0200 Subject: [PATCH 4/8] minor fixes and enable datalist elements in OSR --- atom/browser/api/atom_api_web_contents.cc | 1 + .../osr/osr_render_widget_host_view.cc | 180 ++++++++++++++++-- .../browser/osr/osr_render_widget_host_view.h | 9 +- atom/browser/osr/osr_view_proxy.cc | 58 ++++++ atom/browser/osr/osr_view_proxy.h | 53 ++++++ atom/browser/ui/autofill_popup.cc | 26 ++- atom/browser/ui/autofill_popup.h | 5 +- atom/browser/ui/views/autofill_popup_view.cc | 109 ++++++++--- atom/browser/ui/views/autofill_popup_view.h | 5 + atom/renderer/atom_autofill_agent.cc | 9 +- atom/renderer/atom_autofill_agent.h | 3 +- filenames.gypi | 2 + 12 files changed, 402 insertions(+), 58 deletions(-) create mode 100644 atom/browser/osr/osr_view_proxy.cc create mode 100644 atom/browser/osr/osr_view_proxy.h diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index eeec33caba49..5b582127b166 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -1635,6 +1635,7 @@ void WebContents::OnShowAutofillPopup( autofill_popup_->CreateView( routing_id, web_contents(), + IsOffScreen() || (embedder_ && embedder_->IsOffScreen()), relay->widget(), bounds); autofill_popup_->SetItems(values, labels); diff --git a/atom/browser/osr/osr_render_widget_host_view.cc b/atom/browser/osr/osr_render_widget_host_view.cc index 605b42ec1d13..005a4755e5b4 100644 --- a/atom/browser/osr/osr_render_widget_host_view.cc +++ b/atom/browser/osr/osr_render_widget_host_view.cc @@ -4,6 +4,7 @@ #include "atom/browser/osr/osr_render_widget_host_view.h" +#include #include #include "base/callback_helpers.h" @@ -22,9 +23,12 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/context_factory.h" #include "media/base/video_frame.h" +#include "third_party/WebKit/public/platform/WebInputEvent.h" #include "ui/compositor/compositor.h" #include "ui/compositor/layer.h" #include "ui/compositor/layer_type.h" +#include "ui/events/base_event_utils.h" +#include "ui/events/event_constants.h" #include "ui/events/latency_info.h" #include "ui/gfx/geometry/dip_util.h" #include "ui/gfx/native_widget_types.h" @@ -37,6 +41,70 @@ namespace { const float kDefaultScaleFactor = 1.0; const int kFrameRetryLimit = 2; +ui::MouseEvent UiMouseEventFromWebMouseEvent(blink::WebMouseEvent event) { + ui::EventType type = ui::EventType::ET_UNKNOWN; + switch (event.type()) { + case blink::WebInputEvent::MouseDown: + type = ui::EventType::ET_MOUSE_PRESSED; + break; + case blink::WebInputEvent::MouseUp: + type = ui::EventType::ET_MOUSE_RELEASED; + break; + case blink::WebInputEvent::MouseMove: + type = ui::EventType::ET_MOUSE_MOVED; + break; + case blink::WebInputEvent::MouseEnter: + type = ui::EventType::ET_MOUSE_ENTERED; + break; + case blink::WebInputEvent::MouseLeave: + type = ui::EventType::ET_MOUSE_EXITED; + break; + case blink::WebInputEvent::MouseWheel: + type = ui::EventType::ET_MOUSEWHEEL; + break; + default: + type = ui::EventType::ET_UNKNOWN; + break; + } + + int button_flags = 0; + switch (event.button) { + case blink::WebMouseEvent::Button::X1: + button_flags |= ui::EventFlags::EF_BACK_MOUSE_BUTTON; + break; + case blink::WebMouseEvent::Button::X2: + button_flags |= ui::EventFlags::EF_FORWARD_MOUSE_BUTTON; + break; + case blink::WebMouseEvent::Button::Left: + button_flags |= ui::EventFlags::EF_LEFT_MOUSE_BUTTON; + break; + case blink::WebMouseEvent::Button::Middle: + button_flags |= ui::EventFlags::EF_MIDDLE_MOUSE_BUTTON; + break; + case blink::WebMouseEvent::Button::Right: + button_flags |= ui::EventFlags::EF_RIGHT_MOUSE_BUTTON; + break; + default: + button_flags = 0; + break; + } + + ui::MouseEvent ui_event(type, + gfx::Point(std::floor(event.x), std::floor(event.y)), + gfx::Point(std::floor(event.x), std::floor(event.y)), + ui::EventTimeForNow(), + button_flags, button_flags); + ui_event.SetClickCount(event.clickCount); + + return ui_event; +} + +ui::MouseWheelEvent UiMouseWheelEventFromWebMouseEvent( + blink::WebMouseWheelEvent event) { + return ui::MouseWheelEvent(UiMouseEventFromWebMouseEvent(event), + std::floor(event.deltaX), std::floor(event.deltaY)); +} + #if !defined(OS_MACOSX) const int kResizeLockTimeoutMs = 67; @@ -619,6 +687,8 @@ void OffScreenRenderWidgetHostView::Destroy() { child_host_view_->CancelWidget(); for (auto guest_host_view : guest_host_views_) guest_host_view->CancelWidget(); + for (auto proxy_view : proxy_views_) + proxy_view->RemoveObserver(); Hide(); } } @@ -835,6 +905,22 @@ void OffScreenRenderWidgetHostView::RemoveGuestHostView( guest_host_views_.erase(guest_host); } +void OffScreenRenderWidgetHostView::AddViewProxy(OffscreenViewProxy* proxy) { + proxy->SetObserver(this); + proxy_views_.insert(proxy); +} + +void OffScreenRenderWidgetHostView::RemoveViewProxy(OffscreenViewProxy* proxy) { + proxy->RemoveObserver(); + proxy_views_.erase(proxy); +} + +void OffScreenRenderWidgetHostView::ProxyViewDestroyed( + OffscreenViewProxy* proxy) { + proxy_views_.erase(proxy); + Invalidate(); +} + void OffScreenRenderWidgetHostView::RegisterGuestViewFrameSwappedCallback( content::RenderWidgetHostViewGuest* guest_host_view) { guest_host_view->RegisterFrameSwappedCallback(base::MakeUnique( @@ -906,12 +992,16 @@ void CopyBitmapTo( char* dest = static_cast(destination.getPixels()); int pixelsize = source.bytesPerPixel(); - if (pos.x() + pos.width() <= destination.width() && - pos.y() + pos.height() <= destination.height()) { - for (int i = 0; i < pos.height(); i++) { + int width = pos.x() + pos.width() <= destination.width() ? pos.width() + : pos.width() - ((pos.x() + pos.width()) - destination.width()); + int height = pos.y() + pos.height() <= destination.height() ? pos.height() + : pos.height() - ((pos.y() + pos.height()) - destination.height()); + + if (width > 0 && height > 0) { + for (int i = 0; i < height; i++) { memcpy(dest + ((pos.y() + i) * destination.width() + pos.x()) * pixelsize, src + (i * source.width()) * pixelsize, - pos.width() * pixelsize); + width * pixelsize); } } @@ -926,19 +1016,41 @@ void OffScreenRenderWidgetHostView::OnPaint( if (parent_callback_) { parent_callback_.Run(damage_rect, bitmap); - } else if (popup_host_view_ && popup_bitmap_.get()) { - gfx::Rect pos = popup_host_view_->popup_position_; - gfx::Rect damage(damage_rect); - damage.Union(pos); - - SkBitmap copy = SkBitmapOperations::CreateTiledBitmap(bitmap, - pos.x(), pos.y(), pos.width(), pos.height()); - - CopyBitmapTo(bitmap, *popup_bitmap_, pos); - callback_.Run(damage, bitmap); - CopyBitmapTo(bitmap, copy, pos); } else { - callback_.Run(damage_rect, bitmap); + gfx::Rect damage(damage_rect); + + std::vector damages; + std::vector bitmaps; + std::vector originals; + + if (popup_host_view_ && popup_bitmap_.get()) { + gfx::Rect pos = popup_host_view_->popup_position_; + damage.Union(pos); + damages.push_back(pos); + bitmaps.push_back(popup_bitmap_.get()); + originals.push_back(SkBitmapOperations::CreateTiledBitmap(bitmap, + pos.x(), pos.y(), pos.width(), pos.height())); + } + + for (auto proxy_view : proxy_views_) { + gfx::Rect pos = proxy_view->GetBounds(); + damage.Union(pos); + damages.push_back(pos); + bitmaps.push_back(proxy_view->GetBitmap()); + originals.push_back(SkBitmapOperations::CreateTiledBitmap(bitmap, + pos.x(), pos.y(), pos.width(), pos.height())); + } + + for (int i = 0; i < damages.size(); i++) { + CopyBitmapTo(bitmap, *(bitmaps[i]), damages[i]); + } + + damage.Intersect(GetViewBounds()); + callback_.Run(damage, bitmap); + + for (int i = 0; i < damages.size(); i++) { + CopyBitmapTo(bitmap, originals[i], damages[i]); + } } ReleaseResize(); @@ -951,6 +1063,11 @@ void OffScreenRenderWidgetHostView::OnPopupPaint( InvalidateBounds(popup_host_view_->popup_position_); } +void OffScreenRenderWidgetHostView::OnProxyViewPaint( + const gfx::Rect& damage_rect) { + InvalidateBounds(damage_rect); +} + void OffScreenRenderWidgetHostView::HoldResize() { if (!hold_resize_) hold_resize_ = true; @@ -992,6 +1109,21 @@ void OffScreenRenderWidgetHostView::ProcessKeyboardEvent( void OffScreenRenderWidgetHostView::ProcessMouseEvent( const blink::WebMouseEvent& event, const ui::LatencyInfo& latency) { + for (auto proxy_view : proxy_views_) { + gfx::Rect bounds = proxy_view->GetBounds(); + if (bounds.Contains(event.x, event.y)) { + blink::WebMouseEvent proxy_event(event); + proxy_event.x -= bounds.x(); + proxy_event.y -= bounds.y(); + proxy_event.windowX = proxy_event.x; + proxy_event.windowY = proxy_event.y; + + ui::MouseEvent ui_event = UiMouseEventFromWebMouseEvent(proxy_event); + proxy_view->OnEvent(&ui_event); + return; + } + } + if (!IsPopupWidget()) { if (popup_host_view_ && popup_host_view_->popup_position_.Contains(event.x, event.y)) { @@ -1005,6 +1137,7 @@ void OffScreenRenderWidgetHostView::ProcessMouseEvent( return; } } + if (!render_widget_host_) return; render_widget_host_->ForwardMouseEvent(event); @@ -1013,6 +1146,21 @@ void OffScreenRenderWidgetHostView::ProcessMouseEvent( void OffScreenRenderWidgetHostView::ProcessMouseWheelEvent( const blink::WebMouseWheelEvent& event, const ui::LatencyInfo& latency) { + for (auto proxy_view : proxy_views_) { + gfx::Rect bounds = proxy_view->GetBounds(); + if (bounds.Contains(event.x, event.y)) { + blink::WebMouseWheelEvent proxy_event(event); + proxy_event.x -= bounds.x(); + proxy_event.y -= bounds.y(); + proxy_event.windowX = proxy_event.x; + proxy_event.windowY = proxy_event.y; + + ui::MouseWheelEvent ui_event = + UiMouseWheelEventFromWebMouseEvent(proxy_event); + proxy_view->OnEvent(&ui_event); + return; + } + } if (!IsPopupWidget()) { if (popup_host_view_) { if (popup_host_view_->popup_position_.Contains(event.x, event.y)) { diff --git a/atom/browser/osr/osr_render_widget_host_view.h b/atom/browser/osr/osr_render_widget_host_view.h index 1f8558db1f9e..dc204a311ff5 100644 --- a/atom/browser/osr/osr_render_widget_host_view.h +++ b/atom/browser/osr/osr_render_widget_host_view.h @@ -16,6 +16,7 @@ #include "atom/browser/native_window.h" #include "atom/browser/native_window_observer.h" #include "atom/browser/osr/osr_output_device.h" +#include "atom/browser/osr/osr_view_proxy.h" #include "base/process/kill.h" #include "base/threading/thread.h" #include "base/time/time.h" @@ -68,7 +69,8 @@ class OffScreenRenderWidgetHostView #if !defined(OS_MACOSX) public content::DelegatedFrameHostClient, #endif - public NativeWindowObserver { + public NativeWindowObserver, + public OffscreenViewProxyObserver { public: OffScreenRenderWidgetHostView(bool transparent, const OnPaintCallback& callback, @@ -208,6 +210,9 @@ class OffScreenRenderWidgetHostView void CancelWidget(); void AddGuestHostView(OffScreenRenderWidgetHostView* guest_host); void RemoveGuestHostView(OffScreenRenderWidgetHostView* guest_host); + void AddViewProxy(OffscreenViewProxy* proxy); + void RemoveViewProxy(OffscreenViewProxy* proxy); + void ProxyViewDestroyed(OffscreenViewProxy* proxy); void RegisterGuestViewFrameSwappedCallback( content::RenderWidgetHostViewGuest* guest_host_view); @@ -216,6 +221,7 @@ class OffScreenRenderWidgetHostView void OnPaint(const gfx::Rect& damage_rect, const SkBitmap& bitmap); void OnPopupPaint(const gfx::Rect& damage_rect, const SkBitmap& bitmap); + void OnProxyViewPaint(const gfx::Rect& damage_rect); bool IsPopupWidget() const { return popup_type_ != blink::WebPopupTypeNone; @@ -273,6 +279,7 @@ class OffScreenRenderWidgetHostView std::unique_ptr popup_bitmap_; OffScreenRenderWidgetHostView* child_host_view_; std::set guest_host_views_; + std::set proxy_views_; NativeWindow* native_window_; OffScreenOutputDevice* software_output_device_; diff --git a/atom/browser/osr/osr_view_proxy.cc b/atom/browser/osr/osr_view_proxy.cc new file mode 100644 index 000000000000..91366b9229e6 --- /dev/null +++ b/atom/browser/osr/osr_view_proxy.cc @@ -0,0 +1,58 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/osr/osr_view_proxy.h" + +namespace atom { + +OffscreenViewProxy::OffscreenViewProxy(views::View* view) + : view_(view), observer_(nullptr) { + view_bitmap_.reset(new SkBitmap); +} + +OffscreenViewProxy::~OffscreenViewProxy() { + if (observer_) { + observer_->ProxyViewDestroyed(this); + } +} + +void OffscreenViewProxy::SetObserver(OffscreenViewProxyObserver* observer) { + if (observer_) { + observer_->ProxyViewDestroyed(this); + } + observer_ = observer; +} + +void OffscreenViewProxy::RemoveObserver() { + observer_ = nullptr; +} + +const SkBitmap* OffscreenViewProxy::GetBitmap() const { + return view_bitmap_.get(); +} + +void OffscreenViewProxy::SetBitmap(const SkBitmap& bitmap) { + if (view_bounds_.width() == bitmap.width() && + view_bounds_.height() == bitmap.height() && + observer_) { + view_bitmap_.reset(new SkBitmap(bitmap)); + observer_->OnProxyViewPaint(view_bounds_); + } +} + +const gfx::Rect& OffscreenViewProxy::GetBounds() { + return view_bounds_; +} + +void OffscreenViewProxy::SetBounds(const gfx::Rect& bounds) { + view_bounds_ = bounds; +} + +void OffscreenViewProxy::OnEvent(ui::Event* event) { + if (view_) { + view_->OnEvent(event); + } +} + +} // namespace atom diff --git a/atom/browser/osr/osr_view_proxy.h b/atom/browser/osr/osr_view_proxy.h new file mode 100644 index 000000000000..f4d6946aba1a --- /dev/null +++ b/atom/browser/osr/osr_view_proxy.h @@ -0,0 +1,53 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_OSR_OSR_VIEW_PROXY_H_ +#define ATOM_BROWSER_OSR_OSR_VIEW_PROXY_H_ + +#include + +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/events/event.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/views/view.h" + +namespace atom { + +class OffscreenViewProxy; + +class OffscreenViewProxyObserver { + public: + virtual void OnProxyViewPaint(const gfx::Rect& damage_rect) = 0; + virtual void ProxyViewDestroyed(OffscreenViewProxy* proxy) = 0; +}; + +class OffscreenViewProxy { + public: + explicit OffscreenViewProxy(views::View* view); + ~OffscreenViewProxy(); + + void SetObserver(OffscreenViewProxyObserver* observer); + void RemoveObserver(); + + const SkBitmap* GetBitmap() const; + void SetBitmap(const SkBitmap& bitmap); + + const gfx::Rect& GetBounds(); + void SetBounds(const gfx::Rect& bounds); + + void OnEvent(ui::Event* event); + + void ResetView() { view_ = nullptr; } + private: + views::View* view_; + + gfx::Rect view_bounds_; + std::unique_ptr view_bitmap_; + + OffscreenViewProxyObserver* observer_; +}; + +} // namespace atom + +#endif // ATOM_BROWSER_OSR_OSR_VIEW_PROXY_H_ diff --git a/atom/browser/ui/autofill_popup.cc b/atom/browser/ui/autofill_popup.cc index e7234206d137..b1adaf6b1d6b 100644 --- a/atom/browser/ui/autofill_popup.cc +++ b/atom/browser/ui/autofill_popup.cc @@ -6,6 +6,8 @@ #include #include +#include "atom/browser/osr/osr_render_widget_host_view.h" +#include "atom/browser/osr/osr_view_proxy.h" #include "atom/browser/ui/autofill_popup.h" #include "atom/common/api/api_messages.h" #include "ui/display/display.h" @@ -100,7 +102,7 @@ display::Display GetDisplayNearestPoint( } // namespace AutofillPopup::AutofillPopup(gfx::NativeView container_view) - : container_view_(container_view) { + : container_view_(container_view), view_(nullptr) { bold_font_list_ = gfx::FontList().DeriveWithWeight(gfx::Font::Weight::BOLD); smaller_font_list_ = @@ -114,27 +116,37 @@ AutofillPopup::~AutofillPopup() { void AutofillPopup::CreateView( int routing_id, content::WebContents* web_contents, + bool offscreen, views::Widget* parent_widget, const gfx::RectF& r) { web_contents_ = web_contents; gfx::Rect lb(std::floor(r.x()), std::floor(r.y() + r.height()), std::floor(r.width()), std::floor(r.height())); gfx::Point menu_position(lb.origin()); + popup_bounds_in_view_ = lb; views::View::ConvertPointToScreen( parent_widget->GetContentsView(), &menu_position); popup_bounds_ = gfx::Rect(menu_position, lb.size()); element_bounds_ = popup_bounds_; - view_.reset(new AutofillPopupView(this, parent_widget)); + Hide(); + view_ = new AutofillPopupView(this, parent_widget); view_->Show(); + if (offscreen) { + auto* osr_rwhv = static_cast( + web_contents->GetRenderWidgetHostView()); + view_->view_proxy_.reset(new OffscreenViewProxy(view_)); + osr_rwhv->AddViewProxy(view_->view_proxy_.get()); + } + frame_routing_id_ = routing_id; } void AutofillPopup::Hide() { - if (view_.get()) { + if (view_) { view_->Hide(); - view_.reset(); + view_ = nullptr; } } @@ -143,7 +155,7 @@ void AutofillPopup::SetItems(const std::vector& values, values_ = values; labels_ = labels; UpdatePopupBounds(); - if (view_.get()) { + if (view_) { view_->OnSuggestionsChanged(); } } @@ -182,6 +194,8 @@ void AutofillPopup::UpdatePopupBounds() { popup_bounds_ = gfx::Rect(popup_x_and_width.first, popup_y_and_height.first, popup_x_and_width.second, popup_y_and_height.second); + popup_bounds_in_view_ = gfx::Rect(popup_bounds_in_view_.origin(), + gfx::Size(popup_x_and_width.second, popup_y_and_height.second)); } int AutofillPopup::GetDesiredPopupHeight() { @@ -222,7 +236,7 @@ const gfx::FontList& AutofillPopup::GetLabelFontListForRow(int index) const { ui::NativeTheme::ColorId AutofillPopup::GetBackgroundColorIDForRow( int index) const { - return index == view_->GetSelectedLine() + return (view_ && index == view_->GetSelectedLine()) ? ui::NativeTheme::kColorId_ResultsTableHoveredBackground : ui::NativeTheme::kColorId_ResultsTableNormalBackground; } diff --git a/atom/browser/ui/autofill_popup.h b/atom/browser/ui/autofill_popup.h index ada50dbd9cfc..dd1722429565 100644 --- a/atom/browser/ui/autofill_popup.h +++ b/atom/browser/ui/autofill_popup.h @@ -23,7 +23,7 @@ class AutofillPopup { ~AutofillPopup(); void CreateView(int routing_id, content::WebContents* web_contents, - views::Widget* widget, const gfx::RectF& bounds); + bool offscreen, views::Widget* widget, const gfx::RectF& bounds); void Hide(); void SetItems(const std::vector& values, @@ -54,6 +54,7 @@ class AutofillPopup { // Popup location gfx::Rect popup_bounds_; + gfx::Rect popup_bounds_in_view_; // Bounds of the autofilled element gfx::Rect element_bounds_; @@ -72,7 +73,7 @@ class AutofillPopup { content::WebContents* web_contents_; // The popup view - std::unique_ptr view_; + AutofillPopupView* view_; DISALLOW_COPY_AND_ASSIGN(AutofillPopup); }; diff --git a/atom/browser/ui/views/autofill_popup_view.cc b/atom/browser/ui/views/autofill_popup_view.cc index 070844872262..829580d0ba96 100644 --- a/atom/browser/ui/views/autofill_popup_view.cc +++ b/atom/browser/ui/views/autofill_popup_view.cc @@ -4,6 +4,7 @@ #include "atom/browser/ui/views/autofill_popup_view.h" #include "base/bind.h" +#include "base/i18n/rtl.h" #include "content/public/browser/render_view_host.h" #include "ui/events/keycodes/keyboard_codes.h" #include "ui/gfx/canvas.h" @@ -21,6 +22,7 @@ AutofillPopupView::AutofillPopupView( views::Widget* parent_widget) : popup_(popup), parent_widget_(parent_widget), + view_proxy_(nullptr), weak_ptr_factory_(this) { CreateChildViews(); SetFocusBehavior(FocusBehavior::ALWAYS); @@ -36,12 +38,19 @@ AutofillPopupView::~AutofillPopupView() { RemoveObserver(); + if (view_proxy_.get()) { + view_proxy_->ResetView(); + } + if (GetWidget()) { GetWidget()->Close(); } } void AutofillPopupView::Show() { + if (!popup_) + return; + const bool initialize_widget = !GetWidget(); if (initialize_widget) { parent_widget_->AddObserver(this); @@ -88,9 +97,11 @@ void AutofillPopupView::Show() { } void AutofillPopupView::Hide() { - auto host = popup_->web_contents_->GetRenderViewHost()->GetWidget(); - host->RemoveKeyPressEventCallback(keypress_callback_); - popup_ = NULL; + if (popup_) { + auto host = popup_->web_contents_->GetRenderViewHost()->GetWidget(); + host->RemoveKeyPressEventCallback(keypress_callback_); + popup_ = NULL; + } RemoveObserver(); @@ -102,11 +113,14 @@ void AutofillPopupView::Hide() { } void AutofillPopupView::OnSuggestionsChanged() { + if (!popup_) + return; + + CreateChildViews(); if (popup_->GetLineCount() == 0) { popup_->Hide(); return; } - CreateChildViews(); DoUpdateBoundsAndRedrawPopup(); } @@ -116,21 +130,25 @@ void AutofillPopupView::OnSelectedRowChanged( SchedulePaint(); if (current_row_selection) { - DCHECK_LT(*current_row_selection, child_count()); - child_at(*current_row_selection) - ->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true); + int selected = current_row_selection.value_or(-1); + if (selected == -1 || selected >= child_count()) + return; + child_at(selected)->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true); } } void AutofillPopupView::DrawAutofillEntry(gfx::Canvas* canvas, int index, const gfx::Rect& entry_rect) { + if (!popup_) + return; + canvas->FillRect( entry_rect, GetNativeTheme()->GetSystemColor( popup_->GetBackgroundColorIDForRow(index))); - const bool is_rtl = false; + const bool is_rtl = base::i18n::IsRTL(); const int text_align = is_rtl ? gfx::Canvas::TEXT_ALIGN_RIGHT : gfx::Canvas::TEXT_ALIGN_LEFT; gfx::Rect value_rect = entry_rect; @@ -174,6 +192,9 @@ void AutofillPopupView::DrawAutofillEntry(gfx::Canvas* canvas, } void AutofillPopupView::CreateChildViews() { + if (!popup_) + return; + RemoveAllChildViews(true); for (int i = 0; i < popup_->GetLineCount(); ++i) { @@ -184,23 +205,39 @@ void AutofillPopupView::CreateChildViews() { } void AutofillPopupView::DoUpdateBoundsAndRedrawPopup() { + if (!popup_) + return; + GetWidget()->SetBounds(popup_->popup_bounds_); SchedulePaint(); } void AutofillPopupView::OnPaint(gfx::Canvas* canvas) { - if (!popup_) + if (!popup_ || popup_->GetLineCount() != child_count()) return; + gfx::Canvas* draw_canvas = canvas; + SkBitmap bitmap; - canvas->DrawColor(GetNativeTheme()->GetSystemColor( + if (view_proxy_.get()) { + bitmap.allocN32Pixels(popup_->popup_bounds_in_view_.width(), + popup_->popup_bounds_in_view_.height(), + true); + draw_canvas = new gfx::Canvas(new SkCanvas(bitmap), 1.0); + } + + draw_canvas->DrawColor(GetNativeTheme()->GetSystemColor( ui::NativeTheme::kColorId_ResultsTableNormalBackground)); - OnPaintBorder(canvas); + OnPaintBorder(draw_canvas); - DCHECK_EQ(popup_->GetLineCount(), child_count()); for (int i = 0; i < popup_->GetLineCount(); ++i) { gfx::Rect line_rect = popup_->GetRowBounds(i); - DrawAutofillEntry(canvas, i, line_rect); + DrawAutofillEntry(draw_canvas, i, line_rect); + } + + if (view_proxy_.get()) { + view_proxy_->SetBounds(popup_->popup_bounds_in_view_); + view_proxy_->SetBitmap(bitmap); } } @@ -292,22 +329,25 @@ void AutofillPopupView::OnGestureEvent(ui::GestureEvent* event) { bool AutofillPopupView::AcceleratorPressed( const ui::Accelerator& accelerator) { - DCHECK_EQ(accelerator.modifiers(), ui::EF_NONE); + if (accelerator.modifiers() != ui::EF_NONE) + return false; if (accelerator.key_code() == ui::VKEY_ESCAPE) { - popup_->Hide(); + if (popup_) + popup_->Hide(); return true; } if (accelerator.key_code() == ui::VKEY_RETURN) return AcceptSelectedLine(); - NOTREACHED(); return false; } bool AutofillPopupView::HandleKeyPressEvent( const content::NativeWebKeyboardEvent& event) { + if (!popup_) + return false; switch (event.windowsKeyCode) { case ui::VKEY_UP: SelectPreviousLine(); @@ -338,43 +378,49 @@ bool AutofillPopupView::HandleKeyPressEvent( } void AutofillPopupView::OnNativeFocusChanged(gfx::NativeView focused_now) { - if (GetWidget() && GetWidget()->GetNativeView() != focused_now) + if (GetWidget() && GetWidget()->GetNativeView() != focused_now && popup_) popup_->Hide(); } void AutofillPopupView::OnWidgetBoundsChanged(views::Widget* widget, const gfx::Rect& new_bounds) { - DCHECK_EQ(widget, parent_widget_); - popup_->Hide(); + if (widget != parent_widget_) + return; + if (popup_) + popup_->Hide(); } void AutofillPopupView::AcceptSuggestion(int index) { + if (!popup_) + return; + popup_->AcceptSuggestion(index); popup_->Hide(); } bool AutofillPopupView::AcceptSelectedLine() { - if (!selected_line_) + if (!selected_line_ || selected_line_.value() >= popup_->GetLineCount()) return false; - DCHECK_LT(*selected_line_, popup_->GetLineCount()); - - AcceptSuggestion(*selected_line_); + AcceptSuggestion(selected_line_.value()); return true; } void AutofillPopupView::AcceptSelection(const gfx::Point& point) { + if (!popup_) + return; + SetSelectedLine(popup_->LineFromY(point.y())); AcceptSelectedLine(); } void AutofillPopupView::SetSelectedLine(base::Optional selected_line) { + if (!popup_) + return; if (selected_line_ == selected_line) return; - - if (selected_line) { - DCHECK_LT(*selected_line, popup_->GetLineCount()); - } + if (selected_line && selected_line.value() >= popup_->GetLineCount()) + return; auto previous_selected_line(selected_line_); selected_line_ = selected_line; @@ -382,10 +428,16 @@ void AutofillPopupView::SetSelectedLine(base::Optional selected_line) { } void AutofillPopupView::SetSelection(const gfx::Point& point) { + if (!popup_) + return; + SetSelectedLine(popup_->LineFromY(point.y())); } void AutofillPopupView::SelectNextLine() { + if (!popup_) + return; + int new_selected_line = selected_line_ ? *selected_line_ + 1 : 0; if (new_selected_line >= popup_->GetLineCount()) new_selected_line = 0; @@ -394,6 +446,9 @@ void AutofillPopupView::SelectNextLine() { } void AutofillPopupView::SelectPreviousLine() { + if (!popup_) + return; + int new_selected_line = selected_line_.value_or(0) - 1; if (new_selected_line < 0) new_selected_line = popup_->GetLineCount() - 1; diff --git a/atom/browser/ui/views/autofill_popup_view.h b/atom/browser/ui/views/autofill_popup_view.h index 392e64273df7..75d93184b06f 100644 --- a/atom/browser/ui/views/autofill_popup_view.h +++ b/atom/browser/ui/views/autofill_popup_view.h @@ -7,6 +7,7 @@ #include "atom/browser/ui/autofill_popup.h" +#include "atom/browser/osr/osr_view_proxy.h" #include "base/optional.h" #include "content/public/browser/native_web_keyboard_event.h" #include "content/public/browser/render_widget_host.h" @@ -76,6 +77,8 @@ class AutofillPopupView : public views::WidgetDelegateView, } private: + friend class AutofillPopup; + void OnSelectedRowChanged(base::Optional previous_row_selection, base::Optional current_row_selection); @@ -135,6 +138,8 @@ class AutofillPopupView : public views::WidgetDelegateView, // The index of the currently selected line base::Optional selected_line_; + std::unique_ptr view_proxy_; + // The registered keypress callback, responsible for switching lines on // key presses content::RenderWidgetHost::KeyPressEventCallback keypress_callback_; diff --git a/atom/renderer/atom_autofill_agent.cc b/atom/renderer/atom_autofill_agent.cc index 4ebe6160b5ad..4d8a96323812 100644 --- a/atom/renderer/atom_autofill_agent.cc +++ b/atom/renderer/atom_autofill_agent.cc @@ -73,6 +73,7 @@ void AutofillAgent::DidChangeScrollOffset() { } void AutofillAgent::FocusedNodeChanged(const blink::WebNode&) { + focused_node_was_last_clicked_ = false; was_focused_before_now_ = false; HidePopup(); } @@ -139,8 +140,6 @@ void AutofillAgent::ShowSuggestions( const ShowSuggestionsOptions& options) { if (!element.isEnabled() || element.isReadOnly()) return; - if (!element.suggestedValue().isEmpty()) - return; const blink::WebInputElement* input_element = toWebInputElement(&element); if (input_element) { if (!input_element->isTextField()) @@ -220,7 +219,7 @@ void AutofillAgent::ShowPopup( void AutofillAgent::OnAcceptSuggestion(base::string16 suggestion) { auto element = render_frame_->GetWebFrame()->document().focusedElement(); if (element.isFormControlElement()) { - toWebInputElement(&element)->setAutofillValue( + toWebInputElement(&element)->setSuggestedValue( blink::WebString::fromUTF16(suggestion)); } } @@ -233,7 +232,9 @@ void AutofillAgent::DoFocusChangeComplete() { if (focused_node_was_last_clicked_ && was_focused_before_now_) { ShowSuggestionsOptions options; options.autofill_on_empty_values = true; - ShowSuggestions(*toWebInputElement(&element), options); + auto input_element = toWebInputElement(&element); + if (input_element) + ShowSuggestions(*input_element, options); } was_focused_before_now_ = true; diff --git a/atom/renderer/atom_autofill_agent.h b/atom/renderer/atom_autofill_agent.h index f06692a78fd0..21d08ec88202 100644 --- a/atom/renderer/atom_autofill_agent.h +++ b/atom/renderer/atom_autofill_agent.h @@ -30,10 +30,9 @@ class AutofillAgent : public content::RenderFrameObserver, void FocusedNodeChanged(const blink::WebNode&) override; private: - class Helper : public content::RenderViewObserver { public: - Helper(AutofillAgent* agent); + explicit Helper(AutofillAgent* agent); // content::RenderViewObserver implementation. void OnDestruct() override {} diff --git a/filenames.gypi b/filenames.gypi index 367c652ee675..f3e9eb06b352 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -244,6 +244,8 @@ 'atom/browser/osr/osr_render_widget_host_view.cc', 'atom/browser/osr/osr_render_widget_host_view.h', 'atom/browser/osr/osr_render_widget_host_view_mac.mm', + 'atom/browser/osr/osr_view_proxy.cc', + 'atom/browser/osr/osr_view_proxy.h', 'atom/browser/net/about_protocol_handler.cc', 'atom/browser/net/about_protocol_handler.h', 'atom/browser/net/asar/asar_protocol_handler.cc', From d5c038a7fb43692f823b3d00c55d75aa9ee84bb4 Mon Sep 17 00:00:00 2001 From: Heilig Benedek Date: Sun, 21 May 2017 20:57:19 +0200 Subject: [PATCH 5/8] ci build fix --- atom/browser/native_window.cc | 8 ++++---- atom/browser/native_window.h | 20 +++++++++++--------- atom/browser/native_window_views.cc | 14 +++++++------- atom/browser/native_window_views.h | 14 +++++++------- 4 files changed, 29 insertions(+), 27 deletions(-) diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 9e2c11aec4ab..f06841cb67ad 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -251,7 +251,7 @@ void NativeWindow::SetSizeConstraints( SetContentSizeConstraints(content_constraints); } -extensions::SizeConstraints NativeWindow::GetSizeConstraints() { +extensions::SizeConstraints NativeWindow::GetSizeConstraints() const { extensions::SizeConstraints content_constraints = GetContentSizeConstraints(); extensions::SizeConstraints window_constraints; if (content_constraints.HasMaximumSize()) { @@ -272,7 +272,7 @@ void NativeWindow::SetContentSizeConstraints( size_constraints_ = size_constraints; } -extensions::SizeConstraints NativeWindow::GetContentSizeConstraints() { +extensions::SizeConstraints NativeWindow::GetContentSizeConstraints() const { return size_constraints_; } @@ -282,7 +282,7 @@ void NativeWindow::SetMinimumSize(const gfx::Size& size) { SetSizeConstraints(size_constraints); } -gfx::Size NativeWindow::GetMinimumSize() { +gfx::Size NativeWindow::GetMinimumSize() const { return GetSizeConstraints().GetMinimumSize(); } @@ -292,7 +292,7 @@ void NativeWindow::SetMaximumSize(const gfx::Size& size) { SetSizeConstraints(size_constraints); } -gfx::Size NativeWindow::GetMaximumSize() { +gfx::Size NativeWindow::GetMaximumSize() const { return GetSizeConstraints().GetMaximumSize(); } diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index b0d25e03f232..f5aa5523bffa 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -98,14 +98,14 @@ class NativeWindow : public base::SupportsUserData, virtual gfx::Rect GetContentBounds(); virtual void SetSizeConstraints( const extensions::SizeConstraints& size_constraints); - virtual extensions::SizeConstraints GetSizeConstraints(); + virtual extensions::SizeConstraints GetSizeConstraints() const; virtual void SetContentSizeConstraints( const extensions::SizeConstraints& size_constraints); - virtual extensions::SizeConstraints GetContentSizeConstraints(); + virtual extensions::SizeConstraints GetContentSizeConstraints() const; virtual void SetMinimumSize(const gfx::Size& size); - virtual gfx::Size GetMinimumSize(); + virtual gfx::Size GetMinimumSize() const; virtual void SetMaximumSize(const gfx::Size& size); - virtual gfx::Size GetMaximumSize(); + virtual gfx::Size GetMaximumSize() const; virtual void SetSheetOffset(const double offsetX, const double offsetY); virtual double GetSheetOffsetX(); virtual double GetSheetOffsetY(); @@ -147,9 +147,9 @@ class NativeWindow : public base::SupportsUserData, virtual void SetMenu(AtomMenuModel* menu); virtual void SetParentWindow(NativeWindow* parent); virtual void SetBrowserView(NativeBrowserView* browser_view) = 0; - virtual gfx::NativeView GetNativeView() = 0; - virtual gfx::NativeWindow GetNativeWindow() = 0; - virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0; + virtual gfx::NativeView GetNativeView() const = 0; + virtual gfx::NativeWindow GetNativeWindow() const = 0; + virtual gfx::AcceleratedWidget GetAcceleratedWidget() const = 0; // Taskbar/Dock APIs. enum ProgressState { @@ -281,8 +281,10 @@ class NativeWindow : public base::SupportsUserData, const std::vector& regions); // Converts between content bounds and window bounds. - virtual gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) = 0; - virtual gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) = 0; + virtual gfx::Rect ContentBoundsToWindowBounds( + const gfx::Rect& bounds) const = 0; + virtual gfx::Rect WindowBoundsToContentBounds( + const gfx::Rect& bounds) const = 0; // Called when the window needs to update its draggable region. virtual void UpdateDraggableRegions( diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index 00f0befd50fa..81a846268211 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -924,11 +924,11 @@ void NativeWindowViews::SetParentWindow(NativeWindow* parent) { #endif } -gfx::NativeView NativeWindowViews::GetNativeView() { +gfx::NativeView NativeWindowViews::GetNativeView() const { return window_->GetNativeView(); } -gfx::NativeWindow NativeWindowViews::GetNativeWindow() { +gfx::NativeWindow NativeWindowViews::GetNativeWindow() const { return window_->GetNativeWindow(); } @@ -999,7 +999,7 @@ bool NativeWindowViews::IsVisibleOnAllWorkspaces() { return false; } -gfx::AcceleratedWidget NativeWindowViews::GetAcceleratedWidget() { +gfx::AcceleratedWidget NativeWindowViews::GetAcceleratedWidget() const { return GetNativeWindow()->GetHost()->GetAcceleratedWidget(); } @@ -1180,7 +1180,7 @@ void NativeWindowViews::OnWidgetMove() { } gfx::Rect NativeWindowViews::ContentBoundsToWindowBounds( - const gfx::Rect& bounds) { + const gfx::Rect& bounds) const { if (!has_frame()) return bounds; @@ -1201,7 +1201,7 @@ gfx::Rect NativeWindowViews::ContentBoundsToWindowBounds( } gfx::Rect NativeWindowViews::WindowBoundsToContentBounds( - const gfx::Rect& bounds) { + const gfx::Rect& bounds) const { if (!has_frame()) return bounds; @@ -1306,11 +1306,11 @@ void NativeWindowViews::Layout() { } } -gfx::Size NativeWindowViews::GetMinimumSize() { +gfx::Size NativeWindowViews::GetMinimumSize() const { return NativeWindow::GetMinimumSize(); } -gfx::Size NativeWindowViews::GetMaximumSize() { +gfx::Size NativeWindowViews::GetMaximumSize() const { return NativeWindow::GetMaximumSize(); } diff --git a/atom/browser/native_window_views.h b/atom/browser/native_window_views.h index 15bdbad18808..a7247e8fe004 100644 --- a/atom/browser/native_window_views.h +++ b/atom/browser/native_window_views.h @@ -106,8 +106,8 @@ class NativeWindowViews : public NativeWindow, void SetMenu(AtomMenuModel* menu_model) override; void SetBrowserView(NativeBrowserView* browser_view) override; void SetParentWindow(NativeWindow* parent) override; - gfx::NativeView GetNativeView() override; - gfx::NativeWindow GetNativeWindow() override; + gfx::NativeView GetNativeView() const override; + gfx::NativeWindow GetNativeWindow() const override; void SetOverlayIcon(const gfx::Image& overlay, const std::string& description) override; void SetProgressBar(double progress, const ProgressState state) override; @@ -118,7 +118,7 @@ class NativeWindowViews : public NativeWindow, void SetVisibleOnAllWorkspaces(bool visible) override; bool IsVisibleOnAllWorkspaces() override; - gfx::AcceleratedWidget GetAcceleratedWidget() override; + gfx::AcceleratedWidget GetAcceleratedWidget() const override; #if defined(OS_WIN) void SetIcon(HICON small_icon, HICON app_icon); @@ -171,16 +171,16 @@ class NativeWindowViews : public NativeWindow, #endif // NativeWindow: - gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) override; - gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) override; + gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) const override; + gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) const override; void HandleKeyboardEvent( content::WebContents*, const content::NativeWebKeyboardEvent& event) override; // views::View: void Layout() override; - gfx::Size GetMinimumSize() override; - gfx::Size GetMaximumSize() override; + gfx::Size GetMinimumSize() const override; + gfx::Size GetMaximumSize() const override; bool AcceleratorPressed(const ui::Accelerator& accelerator) override; // Register accelerators supported by the menu model. From df911593d8c43a8b70764afaf5e7054c263b5dab Mon Sep 17 00:00:00 2001 From: Heilig Benedek Date: Sun, 21 May 2017 22:36:10 +0200 Subject: [PATCH 6/8] Fix menubar animations being incorrect in RTL layout --- atom/browser/ui/views/menu_bar.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/browser/ui/views/menu_bar.cc b/atom/browser/ui/views/menu_bar.cc index 5d9b7152788f..e403b0737809 100644 --- a/atom/browser/ui/views/menu_bar.cc +++ b/atom/browser/ui/views/menu_bar.cc @@ -119,7 +119,7 @@ bool MenuBar::GetMenuButtonFromScreenPoint(const gfx::Point& point, for (int i = 0; i < child_count(); ++i) { views::View* view = child_at(i); - if (view->bounds().Contains(location) && + if (view->GetMirroredBounds().Contains(location) && (menu_model_->GetTypeAt(i) == AtomMenuModel::TYPE_SUBMENU)) { *menu_model = menu_model_->GetSubmenuModelAt(i); *button = static_cast(view); From 039908a244a2b1862cff1322aeee25d56e8a03eb Mon Sep 17 00:00:00 2001 From: gellert Date: Tue, 23 May 2017 11:41:59 +0200 Subject: [PATCH 7/8] various fixes for macos --- atom/browser/native_window_mac.h | 10 +++++----- atom/browser/native_window_mac.mm | 10 +++++----- atom/browser/osr/osr_render_widget_host_view.cc | 4 ++-- atom/browser/ui/autofill_popup.cc | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h index 69bf3afef65a..b5271e4d4364 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -89,9 +89,9 @@ class NativeWindowMac : public NativeWindow, void SetContentProtection(bool enable) override; void SetBrowserView(NativeBrowserView* browser_view) override; void SetParentWindow(NativeWindow* parent) override; - gfx::NativeView GetNativeView() override; - gfx::NativeWindow GetNativeWindow() override; - gfx::AcceleratedWidget GetAcceleratedWidget() override; + gfx::NativeView GetNativeView() const override; + gfx::NativeWindow GetNativeWindow() const override; + gfx::AcceleratedWidget GetAcceleratedWidget() const override; void SetProgressBar(double progress, const ProgressState state) override; void SetOverlayIcon(const gfx::Image& overlay, const std::string& description) override; @@ -140,8 +140,8 @@ class NativeWindowMac : public NativeWindow, private: // NativeWindow: - gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds); - gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds); + gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) const; + gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) const; void UpdateDraggableRegions( const std::vector& regions) override; diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 755e46c4f326..e5192c8b6293 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -1314,15 +1314,15 @@ void NativeWindowMac::SetParentWindow(NativeWindow* parent) { [parent->GetNativeWindow() addChildWindow:window_ ordered:NSWindowAbove]; } -gfx::NativeView NativeWindowMac::GetNativeView() { +gfx::NativeView NativeWindowMac::GetNativeView() const { return inspectable_web_contents()->GetView()->GetNativeView(); } -gfx::NativeWindow NativeWindowMac::GetNativeWindow() { +gfx::NativeWindow NativeWindowMac::GetNativeWindow() const { return window_; } -gfx::AcceleratedWidget NativeWindowMac::GetAcceleratedWidget() { +gfx::AcceleratedWidget NativeWindowMac::GetAcceleratedWidget() const { return inspectable_web_contents()->GetView()->GetNativeView(); } @@ -1498,7 +1498,7 @@ std::vector NativeWindowMac::CalculateNonDraggableRegions( } gfx::Rect NativeWindowMac::ContentBoundsToWindowBounds( - const gfx::Rect& bounds) { + const gfx::Rect& bounds) const { if (has_frame()) { gfx::Rect window_bounds( [window_ frameRectForContentRect:bounds.ToCGRect()]); @@ -1511,7 +1511,7 @@ gfx::Rect NativeWindowMac::ContentBoundsToWindowBounds( } gfx::Rect NativeWindowMac::WindowBoundsToContentBounds( - const gfx::Rect& bounds) { + const gfx::Rect& bounds) const { if (has_frame()) { gfx::Rect content_bounds( [window_ contentRectForFrameRect:bounds.ToCGRect()]); diff --git a/atom/browser/osr/osr_render_widget_host_view.cc b/atom/browser/osr/osr_render_widget_host_view.cc index 005a4755e5b4..11523a660b8f 100644 --- a/atom/browser/osr/osr_render_widget_host_view.cc +++ b/atom/browser/osr/osr_render_widget_host_view.cc @@ -1041,14 +1041,14 @@ void OffScreenRenderWidgetHostView::OnPaint( pos.x(), pos.y(), pos.width(), pos.height())); } - for (int i = 0; i < damages.size(); i++) { + for (size_t i = 0; i < damages.size(); i++) { CopyBitmapTo(bitmap, *(bitmaps[i]), damages[i]); } damage.Intersect(GetViewBounds()); callback_.Run(damage, bitmap); - for (int i = 0; i < damages.size(); i++) { + for (size_t i = 0; i < damages.size(); i++) { CopyBitmapTo(bitmap, originals[i], damages[i]); } } diff --git a/atom/browser/ui/autofill_popup.cc b/atom/browser/ui/autofill_popup.cc index b1adaf6b1d6b..db787003bdee 100644 --- a/atom/browser/ui/autofill_popup.cc +++ b/atom/browser/ui/autofill_popup.cc @@ -205,7 +205,7 @@ int AutofillPopup::GetDesiredPopupHeight() { int AutofillPopup::GetDesiredPopupWidth() { int popup_width = element_bounds_.width(); - for (int i = 0; i < values_.size(); ++i) { + for (size_t i = 0; i < values_.size(); ++i) { int row_size = kEndPadding + 2 * kPopupBorderThickness + gfx::GetStringWidth(GetValueAt(i), GetValueFontListForRow(i)) + gfx::GetStringWidth(GetLabelAt(i), GetLabelFontListForRow(i)); @@ -256,7 +256,7 @@ base::string16 AutofillPopup::GetLabelAt(int i) { int AutofillPopup::LineFromY(int y) const { int current_height = kPopupBorderThickness; - for (int i = 0; i < values_.size(); ++i) { + for (size_t i = 0; i < values_.size(); ++i) { current_height += kRowHeight; if (y <= current_height) From 192cd7787bd8e8116113adbf64bf29930bbd39d6 Mon Sep 17 00:00:00 2001 From: Heilig Benedek Date: Fri, 26 May 2017 03:38:27 +0200 Subject: [PATCH 8/8] move popup related code to nativewindow --- atom/browser/api/atom_api_web_contents.cc | 57 ++++++++------------ atom/browser/api/atom_api_web_contents.h | 13 ++--- atom/browser/native_window.h | 8 +++ atom/browser/native_window_views.cc | 23 ++++++++ atom/browser/native_window_views.h | 9 ++++ atom/browser/ui/autofill_popup.cc | 13 ++--- atom/browser/ui/autofill_popup.h | 9 ++-- atom/browser/ui/views/autofill_popup_view.cc | 14 ++--- atom/common/api/api_messages.h | 10 ++-- atom/renderer/atom_autofill_agent.cc | 29 ++++------ atom/renderer/atom_autofill_agent.h | 9 +--- 11 files changed, 95 insertions(+), 99 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 5b582127b166..659daae18b91 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -17,7 +17,6 @@ #include "atom/browser/child_web_contents_tracker.h" #include "atom/browser/lib/bluetooth_chooser.h" #include "atom/browser/native_window.h" -#include "atom/browser/native_window_views.h" #include "atom/browser/net/atom_network_delegate.h" #include "atom/browser/osr/osr_output_device.h" #include "atom/browser/osr/osr_render_widget_host_view.h" @@ -84,7 +83,6 @@ #include "third_party/WebKit/public/web/WebFindOptions.h" #include "ui/display/screen.h" #include "ui/events/base_event_utils.h" -#include "ui/gfx/geometry/rect_f.h" #if !defined(OS_MACOSX) #include "ui/aura/window.h" @@ -443,8 +441,6 @@ void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate, registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING, content::Source(controller)); - autofill_popup_ = new AutofillPopup(web_contents->GetNativeView()); - Init(isolate); AttachAsUserData(web_contents); } @@ -744,17 +740,6 @@ void WebContents::RenderViewCreated(content::RenderViewHost* render_view_host) { impl->disable_hidden_ = !background_throttling_; } -void WebContents::RenderFrameCreated(content::RenderFrameHost* host) { - Send(new AtomAutofillViewHostMsg_RoutingId( - host->GetRoutingID(), routing_id())); -} - -void WebContents::RenderFrameHostChanged(content::RenderFrameHost* old_host, - content::RenderFrameHost* new_host) { - Send(new AtomAutofillViewHostMsg_RoutingId( - new_host->GetRoutingID(), routing_id())); -} - void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) { Emit("render-view-deleted", render_view_host->GetProcess()->GetID()); } @@ -991,8 +976,23 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) { OnGetZoomLevel) IPC_MESSAGE_HANDLER_CODE(ViewHostMsg_SetCursor, OnCursorChange, handled = false) - IPC_MESSAGE_HANDLER(AtomAutofillViewMsg_ShowPopup, OnShowAutofillPopup) - IPC_MESSAGE_HANDLER(AtomAutofillViewMsg_HidePopup, OnHideAutofillPopup) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + + return handled; +} + +bool WebContents::OnMessageReceived(const IPC::Message& message, + content::RenderFrameHost* frame_host) { + bool handled = true; + auto relay = NativeWindowRelay::FromWebContents(web_contents()); + if (!relay) + return false; + IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(NativeWindow, message, frame_host) + IPC_MESSAGE_FORWARD(AtomAutofillFrameHostMsg_ShowPopup, + relay->window.get(), NativeWindow::ShowAutofillPopup) + IPC_MESSAGE_FORWARD(AtomAutofillFrameHostMsg_HidePopup, + relay->window.get(), NativeWindow::HideAutofillPopup) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -1625,25 +1625,6 @@ void WebContents::OnCursorChange(const content::WebCursor& cursor) { } } -void WebContents::OnShowAutofillPopup( - int routing_id, - const gfx::RectF& bounds, - const std::vector& values, - const std::vector& labels) { - auto relay = reinterpret_cast( - NativeWindow::FromWebContents(web_contents())); - autofill_popup_->CreateView( - routing_id, - web_contents(), - IsOffScreen() || (embedder_ && embedder_->IsOffScreen()), - relay->widget(), - bounds); - autofill_popup_->SetItems(values, labels); -} -void WebContents::OnHideAutofillPopup() { - autofill_popup_->Hide(); -} - void WebContents::SetSize(const SetSizeParams& params) { if (guest_delegate_) guest_delegate_->SetSize(params); @@ -1657,6 +1638,10 @@ bool WebContents::IsOffScreen() const { return type_ == OFF_SCREEN; } +bool WebContents::IsOffScreenOrEmbedderOffscreen() const { + return IsOffScreen() || (embedder_ && embedder_->IsOffScreen()); +} + void WebContents::OnPaint(const gfx::Rect& dirty_rect, const SkBitmap& bitmap) { Emit("paint", dirty_rect, gfx::Image::CreateFrom1xBitmap(bitmap)); } diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 65741f9d0544..3c8124bf4994 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -181,6 +181,7 @@ class WebContents : public mate::TrackableObject, // Methods for offscreen rendering bool IsOffScreen() const; + bool IsOffScreenOrEmbedderOffscreen() const; void OnPaint(const gfx::Rect& dirty_rect, const SkBitmap& bitmap); void StartPainting(); void StopPainting(); @@ -308,9 +309,6 @@ class WebContents : public mate::TrackableObject, // content::WebContentsObserver: void BeforeUnloadFired(const base::TimeTicks& proceed_time) override; void RenderViewCreated(content::RenderViewHost*) override; - void RenderFrameCreated(content::RenderFrameHost*) override; - void RenderFrameHostChanged(content::RenderFrameHost*, - content::RenderFrameHost*) override; void RenderViewDeleted(content::RenderViewHost*) override; void RenderProcessGone(base::TerminationStatus status) override; void DocumentLoadedInFrame( @@ -333,6 +331,8 @@ class WebContents : public mate::TrackableObject, void DidFinishNavigation( content::NavigationHandle* navigation_handle) override; bool OnMessageReceived(const IPC::Message& message) override; + bool OnMessageReceived(const IPC::Message& message, + content::RenderFrameHost* frame_host) override; void WebContentsDestroyed() override; void NavigationEntryCommitted( const content::LoadCommittedDetails& load_details) override; @@ -378,12 +378,6 @@ class WebContents : public mate::TrackableObject, // Called when we receive a CursorChange message from chromium. void OnCursorChange(const content::WebCursor& cursor); - void OnShowAutofillPopup(int routing_id, - const gfx::RectF& bounds, - const std::vector& values, - const std::vector& labels); - void OnHideAutofillPopup(); - // Called when received a message from renderer. void OnRendererMessage(const base::string16& channel, const base::ListValue& args); @@ -407,7 +401,6 @@ class WebContents : public mate::TrackableObject, std::unique_ptr dialog_manager_; std::unique_ptr guest_delegate_; - AutofillPopup* autofill_popup_; // The host webcontents that may contain this webcontents. WebContents* embedder_; diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index f5aa5523bffa..89eacdb05d78 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -18,10 +18,12 @@ #include "base/observer_list.h" #include "base/supports_user_data.h" #include "content/public/browser/readback_types.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_user_data.h" #include "extensions/browser/app_window/size_constraints.h" #include "native_mate/persistent_dictionary.h" +#include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/image/image.h" #include "ui/gfx/image/image_skia.h" @@ -215,6 +217,12 @@ class NativeWindow : public base::SupportsUserData, virtual void HandleKeyboardEvent( content::WebContents*, const content::NativeWebKeyboardEvent& event) {} + virtual void ShowAutofillPopup( + content::RenderFrameHost* frame_host, + const gfx::RectF& bounds, + const std::vector& values, + const std::vector& labels) {} + virtual void HideAutofillPopup(content::RenderFrameHost* frame_host) {} // Public API used by platform-dependent delegates and observers to send UI // related notifications. diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index 81a846268211..242f11212850 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -7,6 +7,7 @@ #include #include +#include "atom/browser/api/atom_api_web_contents.h" #include "atom/browser/native_browser_view_views.h" #include "atom/browser/ui/views/menu_bar.h" #include "atom/browser/window_list.h" @@ -319,6 +320,8 @@ NativeWindowViews::NativeWindowViews( window_->CenterWindow(size); Layout(); + autofill_popup_.reset(new AutofillPopup(GetNativeView())); + #if defined(OS_WIN) // Save initial window state. if (fullscreen) @@ -1269,6 +1272,26 @@ void NativeWindowViews::HandleKeyboardEvent( } } +void NativeWindowViews::ShowAutofillPopup( + content::RenderFrameHost* frame_host, + const gfx::RectF& bounds, + const std::vector& values, + const std::vector& labels) { + auto wc = atom::api::WebContents::FromWrappedClass( + v8::Isolate::GetCurrent(), web_contents()); + autofill_popup_->CreateView( + frame_host, + wc->IsOffScreenOrEmbedderOffscreen(), + widget(), + bounds); + autofill_popup_->SetItems(values, labels); +} + +void NativeWindowViews::HideAutofillPopup( + content::RenderFrameHost* frame_host) { + autofill_popup_->Hide(); +} + void NativeWindowViews::Layout() { const auto size = GetContentsBounds().size(); const auto menu_bar_bounds = diff --git a/atom/browser/native_window_views.h b/atom/browser/native_window_views.h index a7247e8fe004..5d94c2255bbe 100644 --- a/atom/browser/native_window_views.h +++ b/atom/browser/native_window_views.h @@ -11,6 +11,7 @@ #include #include "atom/browser/ui/accelerator_util.h" +#include "atom/browser/ui/autofill_popup.h" #include "ui/views/widget/widget_delegate.h" #include "ui/views/widget/widget_observer.h" @@ -176,6 +177,12 @@ class NativeWindowViews : public NativeWindow, void HandleKeyboardEvent( content::WebContents*, const content::NativeWebKeyboardEvent& event) override; + void ShowAutofillPopup( + content::RenderFrameHost* frame_host, + const gfx::RectF& bounds, + const std::vector& values, + const std::vector& labels) override; + void HideAutofillPopup(content::RenderFrameHost* frame_host) override; // views::View: void Layout() override; @@ -194,6 +201,8 @@ class NativeWindowViews : public NativeWindow, NativeBrowserView* browser_view_; + std::unique_ptr autofill_popup_; + std::unique_ptr menu_bar_; bool menu_bar_autohide_; bool menu_bar_visible_; diff --git a/atom/browser/ui/autofill_popup.cc b/atom/browser/ui/autofill_popup.cc index db787003bdee..f58c0cf884a8 100644 --- a/atom/browser/ui/autofill_popup.cc +++ b/atom/browser/ui/autofill_popup.cc @@ -114,12 +114,11 @@ AutofillPopup::~AutofillPopup() { } void AutofillPopup::CreateView( - int routing_id, - content::WebContents* web_contents, + content::RenderFrameHost* frame_host, bool offscreen, views::Widget* parent_widget, const gfx::RectF& r) { - web_contents_ = web_contents; + frame_host_ = frame_host; gfx::Rect lb(std::floor(r.x()), std::floor(r.y() + r.height()), std::floor(r.width()), std::floor(r.height())); gfx::Point menu_position(lb.origin()); @@ -135,12 +134,10 @@ void AutofillPopup::CreateView( if (offscreen) { auto* osr_rwhv = static_cast( - web_contents->GetRenderWidgetHostView()); + frame_host_->GetView()); view_->view_proxy_.reset(new OffscreenViewProxy(view_)); osr_rwhv->AddViewProxy(view_->view_proxy_.get()); } - - frame_routing_id_ = routing_id; } void AutofillPopup::Hide() { @@ -161,8 +158,8 @@ void AutofillPopup::SetItems(const std::vector& values, } void AutofillPopup::AcceptSuggestion(int index) { - web_contents_->Send(new AtomAutofillViewMsg_AcceptSuggestion( - frame_routing_id_, GetValueAt(index))); + frame_host_->Send(new AtomAutofillFrameMsg_AcceptSuggestion( + frame_host_->GetRoutingID(), GetValueAt(index))); } void AutofillPopup::UpdatePopupBounds() { diff --git a/atom/browser/ui/autofill_popup.h b/atom/browser/ui/autofill_popup.h index dd1722429565..2dc6b68c248a 100644 --- a/atom/browser/ui/autofill_popup.h +++ b/atom/browser/ui/autofill_popup.h @@ -8,7 +8,7 @@ #include #include "atom/browser/ui/views/autofill_popup_view.h" -#include "content/public/browser/web_contents.h" +#include "content/public/browser/render_frame_host.h" #include "ui/gfx/font_list.h" #include "ui/native_theme/native_theme.h" #include "ui/views/widget/widget.h" @@ -22,7 +22,7 @@ class AutofillPopup { explicit AutofillPopup(gfx::NativeView); ~AutofillPopup(); - void CreateView(int routing_id, content::WebContents* web_contents, + void CreateView(content::RenderFrameHost* render_frame, bool offscreen, views::Widget* widget, const gfx::RectF& bounds); void Hide(); @@ -69,10 +69,9 @@ class AutofillPopup { // For sending the accepted suggestion to the render frame that // asked to open the popup - int frame_routing_id_; - content::WebContents* web_contents_; + content::RenderFrameHost* frame_host_; - // The popup view + // The popup view. The lifetime is managed by the owning Widget AutofillPopupView* view_; DISALLOW_COPY_AND_ASSIGN(AutofillPopup); diff --git a/atom/browser/ui/views/autofill_popup_view.cc b/atom/browser/ui/views/autofill_popup_view.cc index 829580d0ba96..e4999b30263f 100644 --- a/atom/browser/ui/views/autofill_popup_view.cc +++ b/atom/browser/ui/views/autofill_popup_view.cc @@ -31,8 +31,9 @@ AutofillPopupView::AutofillPopupView( AutofillPopupView::~AutofillPopupView() { if (popup_) { - auto host = popup_->web_contents_->GetRenderViewHost()->GetWidget(); + auto host = popup_->frame_host_->GetRenderViewHost()->GetWidget(); host->RemoveKeyPressEventCallback(keypress_callback_); + popup_->view_ = nullptr; popup_ = nullptr; } @@ -92,23 +93,24 @@ void AutofillPopupView::Show() { keypress_callback_ = base::Bind(&AutofillPopupView::HandleKeyPressEvent, base::Unretained(this)); - auto host = popup_->web_contents_->GetRenderViewHost()->GetWidget(); + auto host = popup_->frame_host_->GetRenderViewHost()->GetWidget(); host->AddKeyPressEventCallback(keypress_callback_); + + NotifyAccessibilityEvent(ui::AX_EVENT_MENU_START, true); } void AutofillPopupView::Hide() { if (popup_) { - auto host = popup_->web_contents_->GetRenderViewHost()->GetWidget(); + auto host = popup_->frame_host_->GetRenderViewHost()->GetWidget(); host->RemoveKeyPressEventCallback(keypress_callback_); - popup_ = NULL; + popup_ = nullptr; } RemoveObserver(); + NotifyAccessibilityEvent(ui::AX_EVENT_MENU_END, true); if (GetWidget()) { GetWidget()->Close(); - } else { - delete this; } } diff --git a/atom/common/api/api_messages.h b/atom/common/api/api_messages.h index accd2eba0f79..cb8f19090333 100644 --- a/atom/common/api/api_messages.h +++ b/atom/common/api/api_messages.h @@ -38,20 +38,16 @@ IPC_MESSAGE_ROUTED3(AtomViewMsg_Message, IPC_MESSAGE_ROUTED0(AtomViewMsg_Offscreen) -IPC_MESSAGE_ROUTED4(AtomAutofillViewMsg_ShowPopup, - int /* routing_id */, +IPC_MESSAGE_ROUTED3(AtomAutofillFrameHostMsg_ShowPopup, gfx::RectF /* bounds */, std::vector /* values */, std::vector /* labels */) -IPC_MESSAGE_ROUTED0(AtomAutofillViewMsg_HidePopup) +IPC_MESSAGE_ROUTED0(AtomAutofillFrameHostMsg_HidePopup) -IPC_MESSAGE_ROUTED1(AtomAutofillViewMsg_AcceptSuggestion, +IPC_MESSAGE_ROUTED1(AtomAutofillFrameMsg_AcceptSuggestion, base::string16 /* suggestion */) -IPC_MESSAGE_ROUTED1(AtomAutofillViewHostMsg_RoutingId, - int /* id */) - // Sent by the renderer when the draggable regions are updated. IPC_MESSAGE_ROUTED1(AtomViewHostMsg_UpdateDraggableRegions, std::vector /* regions */) diff --git a/atom/renderer/atom_autofill_agent.cc b/atom/renderer/atom_autofill_agent.cc index 4d8a96323812..83d1e2cf8793 100644 --- a/atom/renderer/atom_autofill_agent.cc +++ b/atom/renderer/atom_autofill_agent.cc @@ -52,16 +52,11 @@ void TrimStringVectorForIPC(std::vector* strings) { AutofillAgent::AutofillAgent( content::RenderFrame* frame) : content::RenderFrameObserver(frame), - render_frame_(frame), helper_(new Helper(this)), focused_node_was_last_clicked_(false), was_focused_before_now_(false), weak_ptr_factory_(this) { - render_frame_->GetWebFrame()->setAutofillClient(this); -} - -AutofillAgent::~AutofillAgent() { - delete helper_; + render_frame()->GetWebFrame()->setAutofillClient(this); } void AutofillAgent::OnDestruct() { @@ -169,7 +164,7 @@ void AutofillAgent::ShowSuggestions( } AutofillAgent::Helper::Helper(AutofillAgent* agent) - : content::RenderViewObserver(agent->render_frame_->GetRenderView()), + : content::RenderViewObserver(agent->render_frame()->GetRenderView()), agent_(agent) { } @@ -184,9 +179,7 @@ void AutofillAgent::Helper::FocusChangeComplete() { bool AutofillAgent::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(AutofillAgent, message) - IPC_MESSAGE_HANDLER(AtomAutofillViewHostMsg_RoutingId, - OnWebContentsRoutingIdReceived) - IPC_MESSAGE_HANDLER(AtomAutofillViewMsg_AcceptSuggestion, + IPC_MESSAGE_HANDLER(AtomAutofillFrameMsg_AcceptSuggestion, OnAcceptSuggestion) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -194,16 +187,12 @@ bool AutofillAgent::OnMessageReceived(const IPC::Message& message) { return handled; } -void AutofillAgent::OnWebContentsRoutingIdReceived(int id) { - web_contents_routing_id_ = id; -} - bool AutofillAgent::IsUserGesture() const { return blink::WebUserGestureIndicator::isProcessingUserGesture(); } void AutofillAgent::HidePopup() { - Send(new AtomAutofillViewMsg_HidePopup(web_contents_routing_id_)); + Send(new AtomAutofillFrameHostMsg_HidePopup(render_frame()->GetRoutingID())); } void AutofillAgent::ShowPopup( @@ -211,13 +200,13 @@ void AutofillAgent::ShowPopup( const std::vector& values, const std::vector& labels) { gfx::RectF bounds = - render_frame_->GetRenderView()->ElementBoundsInWindow(element); - Send(new AtomAutofillViewMsg_ShowPopup( - web_contents_routing_id_, routing_id(), bounds, values, labels)); + render_frame()->GetRenderView()->ElementBoundsInWindow(element); + Send(new AtomAutofillFrameHostMsg_ShowPopup( + render_frame()->GetRoutingID(), bounds, values, labels)); } void AutofillAgent::OnAcceptSuggestion(base::string16 suggestion) { - auto element = render_frame_->GetWebFrame()->document().focusedElement(); + auto element = render_frame()->GetWebFrame()->document().focusedElement(); if (element.isFormControlElement()) { toWebInputElement(&element)->setSuggestedValue( blink::WebString::fromUTF16(suggestion)); @@ -225,7 +214,7 @@ void AutofillAgent::OnAcceptSuggestion(base::string16 suggestion) { } void AutofillAgent::DoFocusChangeComplete() { - auto element = render_frame_->GetWebFrame()->document().focusedElement(); + auto element = render_frame()->GetWebFrame()->document().focusedElement(); if (element.isNull() || !element.isFormControlElement()) return; diff --git a/atom/renderer/atom_autofill_agent.h b/atom/renderer/atom_autofill_agent.h index 21d08ec88202..81d685b05ccb 100644 --- a/atom/renderer/atom_autofill_agent.h +++ b/atom/renderer/atom_autofill_agent.h @@ -18,10 +18,9 @@ namespace atom { class AutofillAgent : public content::RenderFrameObserver, - public blink::WebAutofillClient { + public blink::WebAutofillClient { public: explicit AutofillAgent(content::RenderFrame* frame); - ~AutofillAgent(); // content::RenderFrameObserver: void OnDestruct() override; @@ -51,7 +50,6 @@ class AutofillAgent : public content::RenderFrameObserver, }; bool OnMessageReceived(const IPC::Message& message) override; - void OnWebContentsRoutingIdReceived(int routing_id); // blink::WebAutofillClient: void textFieldDidEndEditing(const blink::WebInputElement&) override; @@ -73,10 +71,7 @@ class AutofillAgent : public content::RenderFrameObserver, void DoFocusChangeComplete(); - content::RenderFrame* render_frame_; - int web_contents_routing_id_; - - Helper* helper_; + std::unique_ptr helper_; // True when the last click was on the focused node. bool focused_node_was_last_clicked_;