minor fixes and enable datalist elements in OSR

This commit is contained in:
Heilig Benedek 2017-05-21 19:55:19 +02:00
parent a95d6b997b
commit 218e28b136
12 changed files with 402 additions and 58 deletions

View file

@ -1635,6 +1635,7 @@ void WebContents::OnShowAutofillPopup(
autofill_popup_->CreateView( autofill_popup_->CreateView(
routing_id, routing_id,
web_contents(), web_contents(),
IsOffScreen() || (embedder_ && embedder_->IsOffScreen()),
relay->widget(), relay->widget(),
bounds); bounds);
autofill_popup_->SetItems(values, labels); autofill_popup_->SetItems(values, labels);

View file

@ -4,6 +4,7 @@
#include "atom/browser/osr/osr_render_widget_host_view.h" #include "atom/browser/osr/osr_render_widget_host_view.h"
#include <algorithm>
#include <vector> #include <vector>
#include "base/callback_helpers.h" #include "base/callback_helpers.h"
@ -22,9 +23,12 @@
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/context_factory.h" #include "content/public/browser/context_factory.h"
#include "media/base/video_frame.h" #include "media/base/video_frame.h"
#include "third_party/WebKit/public/platform/WebInputEvent.h"
#include "ui/compositor/compositor.h" #include "ui/compositor/compositor.h"
#include "ui/compositor/layer.h" #include "ui/compositor/layer.h"
#include "ui/compositor/layer_type.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/events/latency_info.h"
#include "ui/gfx/geometry/dip_util.h" #include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/native_widget_types.h" #include "ui/gfx/native_widget_types.h"
@ -37,6 +41,70 @@ namespace {
const float kDefaultScaleFactor = 1.0; const float kDefaultScaleFactor = 1.0;
const int kFrameRetryLimit = 2; 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) #if !defined(OS_MACOSX)
const int kResizeLockTimeoutMs = 67; const int kResizeLockTimeoutMs = 67;
@ -619,6 +687,8 @@ void OffScreenRenderWidgetHostView::Destroy() {
child_host_view_->CancelWidget(); child_host_view_->CancelWidget();
for (auto guest_host_view : guest_host_views_) for (auto guest_host_view : guest_host_views_)
guest_host_view->CancelWidget(); guest_host_view->CancelWidget();
for (auto proxy_view : proxy_views_)
proxy_view->RemoveObserver();
Hide(); Hide();
} }
} }
@ -835,6 +905,22 @@ void OffScreenRenderWidgetHostView::RemoveGuestHostView(
guest_host_views_.erase(guest_host); 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( void OffScreenRenderWidgetHostView::RegisterGuestViewFrameSwappedCallback(
content::RenderWidgetHostViewGuest* guest_host_view) { content::RenderWidgetHostViewGuest* guest_host_view) {
guest_host_view->RegisterFrameSwappedCallback(base::MakeUnique<base::Closure>( guest_host_view->RegisterFrameSwappedCallback(base::MakeUnique<base::Closure>(
@ -906,12 +992,16 @@ void CopyBitmapTo(
char* dest = static_cast<char*>(destination.getPixels()); char* dest = static_cast<char*>(destination.getPixels());
int pixelsize = source.bytesPerPixel(); int pixelsize = source.bytesPerPixel();
if (pos.x() + pos.width() <= destination.width() && int width = pos.x() + pos.width() <= destination.width() ? pos.width()
pos.y() + pos.height() <= destination.height()) { : pos.width() - ((pos.x() + pos.width()) - destination.width());
for (int i = 0; i < pos.height(); i++) { 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, memcpy(dest + ((pos.y() + i) * destination.width() + pos.x()) * pixelsize,
src + (i * source.width()) * pixelsize, src + (i * source.width()) * pixelsize,
pos.width() * pixelsize); width * pixelsize);
} }
} }
@ -926,19 +1016,41 @@ void OffScreenRenderWidgetHostView::OnPaint(
if (parent_callback_) { if (parent_callback_) {
parent_callback_.Run(damage_rect, bitmap); 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 { } else {
callback_.Run(damage_rect, bitmap); gfx::Rect damage(damage_rect);
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()));
}
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(); ReleaseResize();
@ -951,6 +1063,11 @@ void OffScreenRenderWidgetHostView::OnPopupPaint(
InvalidateBounds(popup_host_view_->popup_position_); InvalidateBounds(popup_host_view_->popup_position_);
} }
void OffScreenRenderWidgetHostView::OnProxyViewPaint(
const gfx::Rect& damage_rect) {
InvalidateBounds(damage_rect);
}
void OffScreenRenderWidgetHostView::HoldResize() { void OffScreenRenderWidgetHostView::HoldResize() {
if (!hold_resize_) if (!hold_resize_)
hold_resize_ = true; hold_resize_ = true;
@ -992,6 +1109,21 @@ void OffScreenRenderWidgetHostView::ProcessKeyboardEvent(
void OffScreenRenderWidgetHostView::ProcessMouseEvent( void OffScreenRenderWidgetHostView::ProcessMouseEvent(
const blink::WebMouseEvent& event, const blink::WebMouseEvent& event,
const ui::LatencyInfo& latency) { 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 (!IsPopupWidget()) {
if (popup_host_view_ && if (popup_host_view_ &&
popup_host_view_->popup_position_.Contains(event.x, event.y)) { popup_host_view_->popup_position_.Contains(event.x, event.y)) {
@ -1005,6 +1137,7 @@ void OffScreenRenderWidgetHostView::ProcessMouseEvent(
return; return;
} }
} }
if (!render_widget_host_) if (!render_widget_host_)
return; return;
render_widget_host_->ForwardMouseEvent(event); render_widget_host_->ForwardMouseEvent(event);
@ -1013,6 +1146,21 @@ void OffScreenRenderWidgetHostView::ProcessMouseEvent(
void OffScreenRenderWidgetHostView::ProcessMouseWheelEvent( void OffScreenRenderWidgetHostView::ProcessMouseWheelEvent(
const blink::WebMouseWheelEvent& event, const blink::WebMouseWheelEvent& event,
const ui::LatencyInfo& latency) { 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 (!IsPopupWidget()) {
if (popup_host_view_) { if (popup_host_view_) {
if (popup_host_view_->popup_position_.Contains(event.x, event.y)) { if (popup_host_view_->popup_position_.Contains(event.x, event.y)) {

View file

@ -16,6 +16,7 @@
#include "atom/browser/native_window.h" #include "atom/browser/native_window.h"
#include "atom/browser/native_window_observer.h" #include "atom/browser/native_window_observer.h"
#include "atom/browser/osr/osr_output_device.h" #include "atom/browser/osr/osr_output_device.h"
#include "atom/browser/osr/osr_view_proxy.h"
#include "base/process/kill.h" #include "base/process/kill.h"
#include "base/threading/thread.h" #include "base/threading/thread.h"
#include "base/time/time.h" #include "base/time/time.h"
@ -68,7 +69,8 @@ class OffScreenRenderWidgetHostView
#if !defined(OS_MACOSX) #if !defined(OS_MACOSX)
public content::DelegatedFrameHostClient, public content::DelegatedFrameHostClient,
#endif #endif
public NativeWindowObserver { public NativeWindowObserver,
public OffscreenViewProxyObserver {
public: public:
OffScreenRenderWidgetHostView(bool transparent, OffScreenRenderWidgetHostView(bool transparent,
const OnPaintCallback& callback, const OnPaintCallback& callback,
@ -208,6 +210,9 @@ class OffScreenRenderWidgetHostView
void CancelWidget(); void CancelWidget();
void AddGuestHostView(OffScreenRenderWidgetHostView* guest_host); void AddGuestHostView(OffScreenRenderWidgetHostView* guest_host);
void RemoveGuestHostView(OffScreenRenderWidgetHostView* guest_host); void RemoveGuestHostView(OffScreenRenderWidgetHostView* guest_host);
void AddViewProxy(OffscreenViewProxy* proxy);
void RemoveViewProxy(OffscreenViewProxy* proxy);
void ProxyViewDestroyed(OffscreenViewProxy* proxy);
void RegisterGuestViewFrameSwappedCallback( void RegisterGuestViewFrameSwappedCallback(
content::RenderWidgetHostViewGuest* guest_host_view); content::RenderWidgetHostViewGuest* guest_host_view);
@ -216,6 +221,7 @@ class OffScreenRenderWidgetHostView
void OnPaint(const gfx::Rect& damage_rect, const SkBitmap& bitmap); void OnPaint(const gfx::Rect& damage_rect, const SkBitmap& bitmap);
void OnPopupPaint(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 { bool IsPopupWidget() const {
return popup_type_ != blink::WebPopupTypeNone; return popup_type_ != blink::WebPopupTypeNone;
@ -273,6 +279,7 @@ class OffScreenRenderWidgetHostView
std::unique_ptr<SkBitmap> popup_bitmap_; std::unique_ptr<SkBitmap> popup_bitmap_;
OffScreenRenderWidgetHostView* child_host_view_; OffScreenRenderWidgetHostView* child_host_view_;
std::set<OffScreenRenderWidgetHostView*> guest_host_views_; std::set<OffScreenRenderWidgetHostView*> guest_host_views_;
std::set<OffscreenViewProxy*> proxy_views_;
NativeWindow* native_window_; NativeWindow* native_window_;
OffScreenOutputDevice* software_output_device_; OffScreenOutputDevice* software_output_device_;

View file

@ -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

View file

@ -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_

View file

@ -6,6 +6,8 @@
#include <utility> #include <utility>
#include <vector> #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/browser/ui/autofill_popup.h"
#include "atom/common/api/api_messages.h" #include "atom/common/api/api_messages.h"
#include "ui/display/display.h" #include "ui/display/display.h"
@ -100,7 +102,7 @@ display::Display GetDisplayNearestPoint(
} // namespace } // namespace
AutofillPopup::AutofillPopup(gfx::NativeView container_view) AutofillPopup::AutofillPopup(gfx::NativeView container_view)
: container_view_(container_view) { : container_view_(container_view), view_(nullptr) {
bold_font_list_ = bold_font_list_ =
gfx::FontList().DeriveWithWeight(gfx::Font::Weight::BOLD); gfx::FontList().DeriveWithWeight(gfx::Font::Weight::BOLD);
smaller_font_list_ = smaller_font_list_ =
@ -114,27 +116,37 @@ AutofillPopup::~AutofillPopup() {
void AutofillPopup::CreateView( void AutofillPopup::CreateView(
int routing_id, int routing_id,
content::WebContents* web_contents, content::WebContents* web_contents,
bool offscreen,
views::Widget* parent_widget, views::Widget* parent_widget,
const gfx::RectF& r) { const gfx::RectF& r) {
web_contents_ = web_contents; 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())); std::floor(r.width()), std::floor(r.height()));
gfx::Point menu_position(lb.origin()); gfx::Point menu_position(lb.origin());
popup_bounds_in_view_ = lb;
views::View::ConvertPointToScreen( views::View::ConvertPointToScreen(
parent_widget->GetContentsView(), &menu_position); parent_widget->GetContentsView(), &menu_position);
popup_bounds_ = gfx::Rect(menu_position, lb.size()); popup_bounds_ = gfx::Rect(menu_position, lb.size());
element_bounds_ = popup_bounds_; element_bounds_ = popup_bounds_;
view_.reset(new AutofillPopupView(this, parent_widget)); Hide();
view_ = new AutofillPopupView(this, parent_widget);
view_->Show(); 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; frame_routing_id_ = routing_id;
} }
void AutofillPopup::Hide() { void AutofillPopup::Hide() {
if (view_.get()) { if (view_) {
view_->Hide(); view_->Hide();
view_.reset(); view_ = nullptr;
} }
} }
@ -143,7 +155,7 @@ void AutofillPopup::SetItems(const std::vector<base::string16>& values,
values_ = values; values_ = values;
labels_ = labels; labels_ = labels;
UpdatePopupBounds(); UpdatePopupBounds();
if (view_.get()) { if (view_) {
view_->OnSuggestionsChanged(); view_->OnSuggestionsChanged();
} }
} }
@ -182,6 +194,8 @@ void AutofillPopup::UpdatePopupBounds() {
popup_bounds_ = gfx::Rect(popup_x_and_width.first, popup_y_and_height.first, 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_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() { int AutofillPopup::GetDesiredPopupHeight() {
@ -222,7 +236,7 @@ const gfx::FontList& AutofillPopup::GetLabelFontListForRow(int index) const {
ui::NativeTheme::ColorId AutofillPopup::GetBackgroundColorIDForRow( ui::NativeTheme::ColorId AutofillPopup::GetBackgroundColorIDForRow(
int index) const { int index) const {
return index == view_->GetSelectedLine() return (view_ && index == view_->GetSelectedLine())
? ui::NativeTheme::kColorId_ResultsTableHoveredBackground ? ui::NativeTheme::kColorId_ResultsTableHoveredBackground
: ui::NativeTheme::kColorId_ResultsTableNormalBackground; : ui::NativeTheme::kColorId_ResultsTableNormalBackground;
} }

View file

@ -23,7 +23,7 @@ class AutofillPopup {
~AutofillPopup(); ~AutofillPopup();
void CreateView(int routing_id, content::WebContents* web_contents, 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 Hide();
void SetItems(const std::vector<base::string16>& values, void SetItems(const std::vector<base::string16>& values,
@ -54,6 +54,7 @@ class AutofillPopup {
// Popup location // Popup location
gfx::Rect popup_bounds_; gfx::Rect popup_bounds_;
gfx::Rect popup_bounds_in_view_;
// Bounds of the autofilled element // Bounds of the autofilled element
gfx::Rect element_bounds_; gfx::Rect element_bounds_;
@ -72,7 +73,7 @@ class AutofillPopup {
content::WebContents* web_contents_; content::WebContents* web_contents_;
// The popup view // The popup view
std::unique_ptr<AutofillPopupView> view_; AutofillPopupView* view_;
DISALLOW_COPY_AND_ASSIGN(AutofillPopup); DISALLOW_COPY_AND_ASSIGN(AutofillPopup);
}; };

View file

@ -4,6 +4,7 @@
#include "atom/browser/ui/views/autofill_popup_view.h" #include "atom/browser/ui/views/autofill_popup_view.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/i18n/rtl.h"
#include "content/public/browser/render_view_host.h" #include "content/public/browser/render_view_host.h"
#include "ui/events/keycodes/keyboard_codes.h" #include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h" #include "ui/gfx/canvas.h"
@ -21,6 +22,7 @@ AutofillPopupView::AutofillPopupView(
views::Widget* parent_widget) views::Widget* parent_widget)
: popup_(popup), : popup_(popup),
parent_widget_(parent_widget), parent_widget_(parent_widget),
view_proxy_(nullptr),
weak_ptr_factory_(this) { weak_ptr_factory_(this) {
CreateChildViews(); CreateChildViews();
SetFocusBehavior(FocusBehavior::ALWAYS); SetFocusBehavior(FocusBehavior::ALWAYS);
@ -36,12 +38,19 @@ AutofillPopupView::~AutofillPopupView() {
RemoveObserver(); RemoveObserver();
if (view_proxy_.get()) {
view_proxy_->ResetView();
}
if (GetWidget()) { if (GetWidget()) {
GetWidget()->Close(); GetWidget()->Close();
} }
} }
void AutofillPopupView::Show() { void AutofillPopupView::Show() {
if (!popup_)
return;
const bool initialize_widget = !GetWidget(); const bool initialize_widget = !GetWidget();
if (initialize_widget) { if (initialize_widget) {
parent_widget_->AddObserver(this); parent_widget_->AddObserver(this);
@ -88,9 +97,11 @@ void AutofillPopupView::Show() {
} }
void AutofillPopupView::Hide() { void AutofillPopupView::Hide() {
auto host = popup_->web_contents_->GetRenderViewHost()->GetWidget(); if (popup_) {
host->RemoveKeyPressEventCallback(keypress_callback_); auto host = popup_->web_contents_->GetRenderViewHost()->GetWidget();
popup_ = NULL; host->RemoveKeyPressEventCallback(keypress_callback_);
popup_ = NULL;
}
RemoveObserver(); RemoveObserver();
@ -102,11 +113,14 @@ void AutofillPopupView::Hide() {
} }
void AutofillPopupView::OnSuggestionsChanged() { void AutofillPopupView::OnSuggestionsChanged() {
if (!popup_)
return;
CreateChildViews();
if (popup_->GetLineCount() == 0) { if (popup_->GetLineCount() == 0) {
popup_->Hide(); popup_->Hide();
return; return;
} }
CreateChildViews();
DoUpdateBoundsAndRedrawPopup(); DoUpdateBoundsAndRedrawPopup();
} }
@ -116,21 +130,25 @@ void AutofillPopupView::OnSelectedRowChanged(
SchedulePaint(); SchedulePaint();
if (current_row_selection) { if (current_row_selection) {
DCHECK_LT(*current_row_selection, child_count()); int selected = current_row_selection.value_or(-1);
child_at(*current_row_selection) if (selected == -1 || selected >= child_count())
->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true); return;
child_at(selected)->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true);
} }
} }
void AutofillPopupView::DrawAutofillEntry(gfx::Canvas* canvas, void AutofillPopupView::DrawAutofillEntry(gfx::Canvas* canvas,
int index, int index,
const gfx::Rect& entry_rect) { const gfx::Rect& entry_rect) {
if (!popup_)
return;
canvas->FillRect( canvas->FillRect(
entry_rect, entry_rect,
GetNativeTheme()->GetSystemColor( GetNativeTheme()->GetSystemColor(
popup_->GetBackgroundColorIDForRow(index))); popup_->GetBackgroundColorIDForRow(index)));
const bool is_rtl = false; const bool is_rtl = base::i18n::IsRTL();
const int text_align = const int text_align =
is_rtl ? gfx::Canvas::TEXT_ALIGN_RIGHT : gfx::Canvas::TEXT_ALIGN_LEFT; is_rtl ? gfx::Canvas::TEXT_ALIGN_RIGHT : gfx::Canvas::TEXT_ALIGN_LEFT;
gfx::Rect value_rect = entry_rect; gfx::Rect value_rect = entry_rect;
@ -174,6 +192,9 @@ void AutofillPopupView::DrawAutofillEntry(gfx::Canvas* canvas,
} }
void AutofillPopupView::CreateChildViews() { void AutofillPopupView::CreateChildViews() {
if (!popup_)
return;
RemoveAllChildViews(true); RemoveAllChildViews(true);
for (int i = 0; i < popup_->GetLineCount(); ++i) { for (int i = 0; i < popup_->GetLineCount(); ++i) {
@ -184,23 +205,39 @@ void AutofillPopupView::CreateChildViews() {
} }
void AutofillPopupView::DoUpdateBoundsAndRedrawPopup() { void AutofillPopupView::DoUpdateBoundsAndRedrawPopup() {
if (!popup_)
return;
GetWidget()->SetBounds(popup_->popup_bounds_); GetWidget()->SetBounds(popup_->popup_bounds_);
SchedulePaint(); SchedulePaint();
} }
void AutofillPopupView::OnPaint(gfx::Canvas* canvas) { void AutofillPopupView::OnPaint(gfx::Canvas* canvas) {
if (!popup_) if (!popup_ || popup_->GetLineCount() != child_count())
return; 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)); ui::NativeTheme::kColorId_ResultsTableNormalBackground));
OnPaintBorder(canvas); OnPaintBorder(draw_canvas);
DCHECK_EQ(popup_->GetLineCount(), child_count());
for (int i = 0; i < popup_->GetLineCount(); ++i) { for (int i = 0; i < popup_->GetLineCount(); ++i) {
gfx::Rect line_rect = popup_->GetRowBounds(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( bool AutofillPopupView::AcceleratorPressed(
const ui::Accelerator& accelerator) { 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) { if (accelerator.key_code() == ui::VKEY_ESCAPE) {
popup_->Hide(); if (popup_)
popup_->Hide();
return true; return true;
} }
if (accelerator.key_code() == ui::VKEY_RETURN) if (accelerator.key_code() == ui::VKEY_RETURN)
return AcceptSelectedLine(); return AcceptSelectedLine();
NOTREACHED();
return false; return false;
} }
bool AutofillPopupView::HandleKeyPressEvent( bool AutofillPopupView::HandleKeyPressEvent(
const content::NativeWebKeyboardEvent& event) { const content::NativeWebKeyboardEvent& event) {
if (!popup_)
return false;
switch (event.windowsKeyCode) { switch (event.windowsKeyCode) {
case ui::VKEY_UP: case ui::VKEY_UP:
SelectPreviousLine(); SelectPreviousLine();
@ -338,43 +378,49 @@ bool AutofillPopupView::HandleKeyPressEvent(
} }
void AutofillPopupView::OnNativeFocusChanged(gfx::NativeView focused_now) { void AutofillPopupView::OnNativeFocusChanged(gfx::NativeView focused_now) {
if (GetWidget() && GetWidget()->GetNativeView() != focused_now) if (GetWidget() && GetWidget()->GetNativeView() != focused_now && popup_)
popup_->Hide(); popup_->Hide();
} }
void AutofillPopupView::OnWidgetBoundsChanged(views::Widget* widget, void AutofillPopupView::OnWidgetBoundsChanged(views::Widget* widget,
const gfx::Rect& new_bounds) { const gfx::Rect& new_bounds) {
DCHECK_EQ(widget, parent_widget_); if (widget != parent_widget_)
popup_->Hide(); return;
if (popup_)
popup_->Hide();
} }
void AutofillPopupView::AcceptSuggestion(int index) { void AutofillPopupView::AcceptSuggestion(int index) {
if (!popup_)
return;
popup_->AcceptSuggestion(index); popup_->AcceptSuggestion(index);
popup_->Hide(); popup_->Hide();
} }
bool AutofillPopupView::AcceptSelectedLine() { bool AutofillPopupView::AcceptSelectedLine() {
if (!selected_line_) if (!selected_line_ || selected_line_.value() >= popup_->GetLineCount())
return false; return false;
DCHECK_LT(*selected_line_, popup_->GetLineCount()); AcceptSuggestion(selected_line_.value());
AcceptSuggestion(*selected_line_);
return true; return true;
} }
void AutofillPopupView::AcceptSelection(const gfx::Point& point) { void AutofillPopupView::AcceptSelection(const gfx::Point& point) {
if (!popup_)
return;
SetSelectedLine(popup_->LineFromY(point.y())); SetSelectedLine(popup_->LineFromY(point.y()));
AcceptSelectedLine(); AcceptSelectedLine();
} }
void AutofillPopupView::SetSelectedLine(base::Optional<int> selected_line) { void AutofillPopupView::SetSelectedLine(base::Optional<int> selected_line) {
if (!popup_)
return;
if (selected_line_ == selected_line) if (selected_line_ == selected_line)
return; return;
if (selected_line && selected_line.value() >= popup_->GetLineCount())
if (selected_line) { return;
DCHECK_LT(*selected_line, popup_->GetLineCount());
}
auto previous_selected_line(selected_line_); auto previous_selected_line(selected_line_);
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) { void AutofillPopupView::SetSelection(const gfx::Point& point) {
if (!popup_)
return;
SetSelectedLine(popup_->LineFromY(point.y())); SetSelectedLine(popup_->LineFromY(point.y()));
} }
void AutofillPopupView::SelectNextLine() { void AutofillPopupView::SelectNextLine() {
if (!popup_)
return;
int new_selected_line = selected_line_ ? *selected_line_ + 1 : 0; int new_selected_line = selected_line_ ? *selected_line_ + 1 : 0;
if (new_selected_line >= popup_->GetLineCount()) if (new_selected_line >= popup_->GetLineCount())
new_selected_line = 0; new_selected_line = 0;
@ -394,6 +446,9 @@ void AutofillPopupView::SelectNextLine() {
} }
void AutofillPopupView::SelectPreviousLine() { void AutofillPopupView::SelectPreviousLine() {
if (!popup_)
return;
int new_selected_line = selected_line_.value_or(0) - 1; int new_selected_line = selected_line_.value_or(0) - 1;
if (new_selected_line < 0) if (new_selected_line < 0)
new_selected_line = popup_->GetLineCount() - 1; new_selected_line = popup_->GetLineCount() - 1;

View file

@ -7,6 +7,7 @@
#include "atom/browser/ui/autofill_popup.h" #include "atom/browser/ui/autofill_popup.h"
#include "atom/browser/osr/osr_view_proxy.h"
#include "base/optional.h" #include "base/optional.h"
#include "content/public/browser/native_web_keyboard_event.h" #include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/render_widget_host.h" #include "content/public/browser/render_widget_host.h"
@ -76,6 +77,8 @@ class AutofillPopupView : public views::WidgetDelegateView,
} }
private: private:
friend class AutofillPopup;
void OnSelectedRowChanged(base::Optional<int> previous_row_selection, void OnSelectedRowChanged(base::Optional<int> previous_row_selection,
base::Optional<int> current_row_selection); base::Optional<int> current_row_selection);
@ -135,6 +138,8 @@ class AutofillPopupView : public views::WidgetDelegateView,
// The index of the currently selected line // The index of the currently selected line
base::Optional<int> selected_line_; base::Optional<int> selected_line_;
std::unique_ptr<OffscreenViewProxy> view_proxy_;
// The registered keypress callback, responsible for switching lines on // The registered keypress callback, responsible for switching lines on
// key presses // key presses
content::RenderWidgetHost::KeyPressEventCallback keypress_callback_; content::RenderWidgetHost::KeyPressEventCallback keypress_callback_;

View file

@ -73,6 +73,7 @@ void AutofillAgent::DidChangeScrollOffset() {
} }
void AutofillAgent::FocusedNodeChanged(const blink::WebNode&) { void AutofillAgent::FocusedNodeChanged(const blink::WebNode&) {
focused_node_was_last_clicked_ = false;
was_focused_before_now_ = false; was_focused_before_now_ = false;
HidePopup(); HidePopup();
} }
@ -139,8 +140,6 @@ void AutofillAgent::ShowSuggestions(
const ShowSuggestionsOptions& options) { const ShowSuggestionsOptions& options) {
if (!element.isEnabled() || element.isReadOnly()) if (!element.isEnabled() || element.isReadOnly())
return; return;
if (!element.suggestedValue().isEmpty())
return;
const blink::WebInputElement* input_element = toWebInputElement(&element); const blink::WebInputElement* input_element = toWebInputElement(&element);
if (input_element) { if (input_element) {
if (!input_element->isTextField()) if (!input_element->isTextField())
@ -220,7 +219,7 @@ void AutofillAgent::ShowPopup(
void AutofillAgent::OnAcceptSuggestion(base::string16 suggestion) { void AutofillAgent::OnAcceptSuggestion(base::string16 suggestion) {
auto element = render_frame_->GetWebFrame()->document().focusedElement(); auto element = render_frame_->GetWebFrame()->document().focusedElement();
if (element.isFormControlElement()) { if (element.isFormControlElement()) {
toWebInputElement(&element)->setAutofillValue( toWebInputElement(&element)->setSuggestedValue(
blink::WebString::fromUTF16(suggestion)); blink::WebString::fromUTF16(suggestion));
} }
} }
@ -233,7 +232,9 @@ void AutofillAgent::DoFocusChangeComplete() {
if (focused_node_was_last_clicked_ && was_focused_before_now_) { if (focused_node_was_last_clicked_ && was_focused_before_now_) {
ShowSuggestionsOptions options; ShowSuggestionsOptions options;
options.autofill_on_empty_values = true; 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; was_focused_before_now_ = true;

View file

@ -30,10 +30,9 @@ class AutofillAgent : public content::RenderFrameObserver,
void FocusedNodeChanged(const blink::WebNode&) override; void FocusedNodeChanged(const blink::WebNode&) override;
private: private:
class Helper : public content::RenderViewObserver { class Helper : public content::RenderViewObserver {
public: public:
Helper(AutofillAgent* agent); explicit Helper(AutofillAgent* agent);
// content::RenderViewObserver implementation. // content::RenderViewObserver implementation.
void OnDestruct() override {} void OnDestruct() override {}

View file

@ -244,6 +244,8 @@
'atom/browser/osr/osr_render_widget_host_view.cc', '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.h',
'atom/browser/osr/osr_render_widget_host_view_mac.mm', '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.cc',
'atom/browser/net/about_protocol_handler.h', 'atom/browser/net/about_protocol_handler.h',
'atom/browser/net/asar/asar_protocol_handler.cc', 'atom/browser/net/asar/asar_protocol_handler.cc',