From 218e28b136124bdad6abd7e763ba89b36910aaca Mon Sep 17 00:00:00 2001 From: Heilig Benedek Date: Sun, 21 May 2017 19:55:19 +0200 Subject: [PATCH] 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 eeec33caba4..5b582127b16 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 605b42ec1d1..005a4755e5b 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 1f8558db1f9..dc204a311ff 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 00000000000..91366b9229e --- /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 00000000000..f4d6946aba1 --- /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 e7234206d13..b1adaf6b1d6 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 ada50dbd9cf..dd172242956 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 07084487226..829580d0ba9 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 392e64273df..75d93184b06 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 4ebe6160b5a..4d8a9632381 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 f06692a78fd..21d08ec8820 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 367c652ee67..f3e9eb06b35 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',