Browse Source

minor fixes and enable datalist elements in OSR

Heilig Benedek 8 years ago
parent
commit
218e28b136

+ 1 - 0
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);

+ 161 - 13
atom/browser/osr/osr_render_widget_host_view.cc

@@ -4,6 +4,7 @@
 
 #include "atom/browser/osr/osr_render_widget_host_view.h"
 
+#include <algorithm>
 #include <vector>
 
 #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<base::Closure>(
@@ -906,12 +992,16 @@ void CopyBitmapTo(
   char* dest = static_cast<char*>(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_;
+  } else {
     gfx::Rect damage(damage_rect);
-    damage.Union(pos);
 
-    SkBitmap copy = SkBitmapOperations::CreateTiledBitmap(bitmap,
-      pos.x(), pos.y(), pos.width(), pos.height());
+    std::vector<gfx::Rect> damages;
+    std::vector<const SkBitmap*> bitmaps;
+    std::vector<SkBitmap> 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()));
+    }
 
-    CopyBitmapTo(bitmap, *popup_bitmap_, pos);
+    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);
-    CopyBitmapTo(bitmap, copy, pos);
-  } else {
-    callback_.Run(damage_rect, 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)) {

+ 8 - 1
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<SkBitmap> popup_bitmap_;
   OffScreenRenderWidgetHostView* child_host_view_;
   std::set<OffScreenRenderWidgetHostView*> guest_host_views_;
+  std::set<OffscreenViewProxy*> proxy_views_;
 
   NativeWindow* native_window_;
   OffScreenOutputDevice* software_output_device_;

+ 58 - 0
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

+ 53 - 0
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 <set>
+
+#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<SkBitmap> view_bitmap_;
+
+  OffscreenViewProxyObserver* observer_;
+};
+
+}  // namespace atom
+
+#endif  // ATOM_BROWSER_OSR_OSR_VIEW_PROXY_H_

+ 20 - 6
atom/browser/ui/autofill_popup.cc

@@ -6,6 +6,8 @@
 #include <utility>
 #include <vector>
 
+#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<OffScreenRenderWidgetHostView*>(
+        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<base::string16>& 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;
 }

+ 3 - 2
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<base::string16>& 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<AutofillPopupView> view_;
+  AutofillPopupView* view_;
 
   DISALLOW_COPY_AND_ASSIGN(AutofillPopup);
 };

+ 82 - 27
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;
+
+  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);
+  }
 
-  canvas->DrawColor(GetNativeTheme()->GetSystemColor(
+  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<int> 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<int> 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;

+ 5 - 0
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<int> previous_row_selection,
                             base::Optional<int> current_row_selection);
 
@@ -135,6 +138,8 @@ class AutofillPopupView : public views::WidgetDelegateView,
   // The index of the currently selected line
   base::Optional<int> selected_line_;
 
+  std::unique_ptr<OffscreenViewProxy> view_proxy_;
+
   // The registered keypress callback, responsible for switching lines on
   // key presses
   content::RenderWidgetHost::KeyPressEventCallback keypress_callback_;

+ 5 - 4
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;

+ 1 - 2
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 {}

+ 2 - 0
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',