Merge pull request #9535 from brenca/datalist-element
Add datalist element support
This commit is contained in:
commit
7d994f2a9e
22 changed files with 1704 additions and 55 deletions
|
@ -982,6 +982,23 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) {
|
|||
return handled;
|
||||
}
|
||||
|
||||
bool WebContents::OnMessageReceived(const IPC::Message& message,
|
||||
content::RenderFrameHost* frame_host) {
|
||||
bool handled = true;
|
||||
auto relay = NativeWindowRelay::FromWebContents(web_contents());
|
||||
if (!relay)
|
||||
return false;
|
||||
IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(NativeWindow, message, frame_host)
|
||||
IPC_MESSAGE_FORWARD(AtomAutofillFrameHostMsg_ShowPopup,
|
||||
relay->window.get(), NativeWindow::ShowAutofillPopup)
|
||||
IPC_MESSAGE_FORWARD(AtomAutofillFrameHostMsg_HidePopup,
|
||||
relay->window.get(), NativeWindow::HideAutofillPopup)
|
||||
IPC_MESSAGE_UNHANDLED(handled = false)
|
||||
IPC_END_MESSAGE_MAP()
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
// There are three ways of destroying a webContents:
|
||||
// 1. call webContents.destroy();
|
||||
// 2. garbage collection;
|
||||
|
@ -1621,6 +1638,10 @@ bool WebContents::IsOffScreen() const {
|
|||
return type_ == OFF_SCREEN;
|
||||
}
|
||||
|
||||
bool WebContents::IsOffScreenOrEmbedderOffscreen() const {
|
||||
return IsOffScreen() || (embedder_ && embedder_->IsOffScreen());
|
||||
}
|
||||
|
||||
void WebContents::OnPaint(const gfx::Rect& dirty_rect, const SkBitmap& bitmap) {
|
||||
Emit("paint", dirty_rect, gfx::Image::CreateFrom1xBitmap(bitmap));
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "atom/browser/api/save_page_handler.h"
|
||||
#include "atom/browser/api/trackable_object.h"
|
||||
#include "atom/browser/common_web_contents_delegate.h"
|
||||
#include "atom/browser/ui/autofill_popup.h"
|
||||
#include "content/common/cursors/webcursor.h"
|
||||
#include "content/public/browser/notification_observer.h"
|
||||
#include "content/public/browser/notification_registrar.h"
|
||||
|
@ -180,6 +181,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
|||
|
||||
// Methods for offscreen rendering
|
||||
bool IsOffScreen() const;
|
||||
bool IsOffScreenOrEmbedderOffscreen() const;
|
||||
void OnPaint(const gfx::Rect& dirty_rect, const SkBitmap& bitmap);
|
||||
void StartPainting();
|
||||
void StopPainting();
|
||||
|
@ -329,6 +331,8 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
|||
void DidFinishNavigation(
|
||||
content::NavigationHandle* navigation_handle) override;
|
||||
bool OnMessageReceived(const IPC::Message& message) override;
|
||||
bool OnMessageReceived(const IPC::Message& message,
|
||||
content::RenderFrameHost* frame_host) override;
|
||||
void WebContentsDestroyed() override;
|
||||
void NavigationEntryCommitted(
|
||||
const content::LoadCommittedDetails& load_details) override;
|
||||
|
|
|
@ -251,7 +251,7 @@ void NativeWindow::SetSizeConstraints(
|
|||
SetContentSizeConstraints(content_constraints);
|
||||
}
|
||||
|
||||
extensions::SizeConstraints NativeWindow::GetSizeConstraints() {
|
||||
extensions::SizeConstraints NativeWindow::GetSizeConstraints() const {
|
||||
extensions::SizeConstraints content_constraints = GetContentSizeConstraints();
|
||||
extensions::SizeConstraints window_constraints;
|
||||
if (content_constraints.HasMaximumSize()) {
|
||||
|
@ -272,7 +272,7 @@ void NativeWindow::SetContentSizeConstraints(
|
|||
size_constraints_ = size_constraints;
|
||||
}
|
||||
|
||||
extensions::SizeConstraints NativeWindow::GetContentSizeConstraints() {
|
||||
extensions::SizeConstraints NativeWindow::GetContentSizeConstraints() const {
|
||||
return size_constraints_;
|
||||
}
|
||||
|
||||
|
@ -282,7 +282,7 @@ void NativeWindow::SetMinimumSize(const gfx::Size& size) {
|
|||
SetSizeConstraints(size_constraints);
|
||||
}
|
||||
|
||||
gfx::Size NativeWindow::GetMinimumSize() {
|
||||
gfx::Size NativeWindow::GetMinimumSize() const {
|
||||
return GetSizeConstraints().GetMinimumSize();
|
||||
}
|
||||
|
||||
|
@ -292,7 +292,7 @@ void NativeWindow::SetMaximumSize(const gfx::Size& size) {
|
|||
SetSizeConstraints(size_constraints);
|
||||
}
|
||||
|
||||
gfx::Size NativeWindow::GetMaximumSize() {
|
||||
gfx::Size NativeWindow::GetMaximumSize() const {
|
||||
return GetSizeConstraints().GetMaximumSize();
|
||||
}
|
||||
|
||||
|
|
|
@ -18,10 +18,12 @@
|
|||
#include "base/observer_list.h"
|
||||
#include "base/supports_user_data.h"
|
||||
#include "content/public/browser/readback_types.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "content/public/browser/web_contents_user_data.h"
|
||||
#include "extensions/browser/app_window/size_constraints.h"
|
||||
#include "native_mate/persistent_dictionary.h"
|
||||
#include "ui/gfx/geometry/rect_f.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
|
||||
|
@ -98,14 +100,14 @@ class NativeWindow : public base::SupportsUserData,
|
|||
virtual gfx::Rect GetContentBounds();
|
||||
virtual void SetSizeConstraints(
|
||||
const extensions::SizeConstraints& size_constraints);
|
||||
virtual extensions::SizeConstraints GetSizeConstraints();
|
||||
virtual extensions::SizeConstraints GetSizeConstraints() const;
|
||||
virtual void SetContentSizeConstraints(
|
||||
const extensions::SizeConstraints& size_constraints);
|
||||
virtual extensions::SizeConstraints GetContentSizeConstraints();
|
||||
virtual extensions::SizeConstraints GetContentSizeConstraints() const;
|
||||
virtual void SetMinimumSize(const gfx::Size& size);
|
||||
virtual gfx::Size GetMinimumSize();
|
||||
virtual gfx::Size GetMinimumSize() const;
|
||||
virtual void SetMaximumSize(const gfx::Size& size);
|
||||
virtual gfx::Size GetMaximumSize();
|
||||
virtual gfx::Size GetMaximumSize() const;
|
||||
virtual void SetSheetOffset(const double offsetX, const double offsetY);
|
||||
virtual double GetSheetOffsetX();
|
||||
virtual double GetSheetOffsetY();
|
||||
|
@ -147,9 +149,9 @@ class NativeWindow : public base::SupportsUserData,
|
|||
virtual void SetMenu(AtomMenuModel* menu);
|
||||
virtual void SetParentWindow(NativeWindow* parent);
|
||||
virtual void SetBrowserView(NativeBrowserView* browser_view) = 0;
|
||||
virtual gfx::NativeView GetNativeView() = 0;
|
||||
virtual gfx::NativeWindow GetNativeWindow() = 0;
|
||||
virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0;
|
||||
virtual gfx::NativeView GetNativeView() const = 0;
|
||||
virtual gfx::NativeWindow GetNativeWindow() const = 0;
|
||||
virtual gfx::AcceleratedWidget GetAcceleratedWidget() const = 0;
|
||||
|
||||
// Taskbar/Dock APIs.
|
||||
enum ProgressState {
|
||||
|
@ -215,6 +217,12 @@ class NativeWindow : public base::SupportsUserData,
|
|||
virtual void HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) {}
|
||||
virtual void ShowAutofillPopup(
|
||||
content::RenderFrameHost* frame_host,
|
||||
const gfx::RectF& bounds,
|
||||
const std::vector<base::string16>& values,
|
||||
const std::vector<base::string16>& labels) {}
|
||||
virtual void HideAutofillPopup(content::RenderFrameHost* frame_host) {}
|
||||
|
||||
// Public API used by platform-dependent delegates and observers to send UI
|
||||
// related notifications.
|
||||
|
@ -281,8 +289,10 @@ class NativeWindow : public base::SupportsUserData,
|
|||
const std::vector<DraggableRegion>& regions);
|
||||
|
||||
// Converts between content bounds and window bounds.
|
||||
virtual gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) = 0;
|
||||
virtual gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) = 0;
|
||||
virtual gfx::Rect ContentBoundsToWindowBounds(
|
||||
const gfx::Rect& bounds) const = 0;
|
||||
virtual gfx::Rect WindowBoundsToContentBounds(
|
||||
const gfx::Rect& bounds) const = 0;
|
||||
|
||||
// Called when the window needs to update its draggable region.
|
||||
virtual void UpdateDraggableRegions(
|
||||
|
|
|
@ -89,9 +89,9 @@ class NativeWindowMac : public NativeWindow,
|
|||
void SetContentProtection(bool enable) override;
|
||||
void SetBrowserView(NativeBrowserView* browser_view) override;
|
||||
void SetParentWindow(NativeWindow* parent) override;
|
||||
gfx::NativeView GetNativeView() override;
|
||||
gfx::NativeWindow GetNativeWindow() override;
|
||||
gfx::AcceleratedWidget GetAcceleratedWidget() override;
|
||||
gfx::NativeView GetNativeView() const override;
|
||||
gfx::NativeWindow GetNativeWindow() const override;
|
||||
gfx::AcceleratedWidget GetAcceleratedWidget() const override;
|
||||
void SetProgressBar(double progress, const ProgressState state) override;
|
||||
void SetOverlayIcon(const gfx::Image& overlay,
|
||||
const std::string& description) override;
|
||||
|
@ -140,8 +140,8 @@ class NativeWindowMac : public NativeWindow,
|
|||
|
||||
private:
|
||||
// NativeWindow:
|
||||
gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds);
|
||||
gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds);
|
||||
gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) const;
|
||||
gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) const;
|
||||
void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) override;
|
||||
|
||||
|
|
|
@ -1314,15 +1314,15 @@ void NativeWindowMac::SetParentWindow(NativeWindow* parent) {
|
|||
[parent->GetNativeWindow() addChildWindow:window_ ordered:NSWindowAbove];
|
||||
}
|
||||
|
||||
gfx::NativeView NativeWindowMac::GetNativeView() {
|
||||
gfx::NativeView NativeWindowMac::GetNativeView() const {
|
||||
return inspectable_web_contents()->GetView()->GetNativeView();
|
||||
}
|
||||
|
||||
gfx::NativeWindow NativeWindowMac::GetNativeWindow() {
|
||||
gfx::NativeWindow NativeWindowMac::GetNativeWindow() const {
|
||||
return window_;
|
||||
}
|
||||
|
||||
gfx::AcceleratedWidget NativeWindowMac::GetAcceleratedWidget() {
|
||||
gfx::AcceleratedWidget NativeWindowMac::GetAcceleratedWidget() const {
|
||||
return inspectable_web_contents()->GetView()->GetNativeView();
|
||||
}
|
||||
|
||||
|
@ -1498,7 +1498,7 @@ std::vector<gfx::Rect> NativeWindowMac::CalculateNonDraggableRegions(
|
|||
}
|
||||
|
||||
gfx::Rect NativeWindowMac::ContentBoundsToWindowBounds(
|
||||
const gfx::Rect& bounds) {
|
||||
const gfx::Rect& bounds) const {
|
||||
if (has_frame()) {
|
||||
gfx::Rect window_bounds(
|
||||
[window_ frameRectForContentRect:bounds.ToCGRect()]);
|
||||
|
@ -1511,7 +1511,7 @@ gfx::Rect NativeWindowMac::ContentBoundsToWindowBounds(
|
|||
}
|
||||
|
||||
gfx::Rect NativeWindowMac::WindowBoundsToContentBounds(
|
||||
const gfx::Rect& bounds) {
|
||||
const gfx::Rect& bounds) const {
|
||||
if (has_frame()) {
|
||||
gfx::Rect content_bounds(
|
||||
[window_ contentRectForFrameRect:bounds.ToCGRect()]);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/api/atom_api_web_contents.h"
|
||||
#include "atom/browser/native_browser_view_views.h"
|
||||
#include "atom/browser/ui/views/menu_bar.h"
|
||||
#include "atom/browser/window_list.h"
|
||||
|
@ -319,6 +320,8 @@ NativeWindowViews::NativeWindowViews(
|
|||
window_->CenterWindow(size);
|
||||
Layout();
|
||||
|
||||
autofill_popup_.reset(new AutofillPopup(GetNativeView()));
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Save initial window state.
|
||||
if (fullscreen)
|
||||
|
@ -924,11 +927,11 @@ void NativeWindowViews::SetParentWindow(NativeWindow* parent) {
|
|||
#endif
|
||||
}
|
||||
|
||||
gfx::NativeView NativeWindowViews::GetNativeView() {
|
||||
gfx::NativeView NativeWindowViews::GetNativeView() const {
|
||||
return window_->GetNativeView();
|
||||
}
|
||||
|
||||
gfx::NativeWindow NativeWindowViews::GetNativeWindow() {
|
||||
gfx::NativeWindow NativeWindowViews::GetNativeWindow() const {
|
||||
return window_->GetNativeWindow();
|
||||
}
|
||||
|
||||
|
@ -999,7 +1002,7 @@ bool NativeWindowViews::IsVisibleOnAllWorkspaces() {
|
|||
return false;
|
||||
}
|
||||
|
||||
gfx::AcceleratedWidget NativeWindowViews::GetAcceleratedWidget() {
|
||||
gfx::AcceleratedWidget NativeWindowViews::GetAcceleratedWidget() const {
|
||||
return GetNativeWindow()->GetHost()->GetAcceleratedWidget();
|
||||
}
|
||||
|
||||
|
@ -1180,7 +1183,7 @@ void NativeWindowViews::OnWidgetMove() {
|
|||
}
|
||||
|
||||
gfx::Rect NativeWindowViews::ContentBoundsToWindowBounds(
|
||||
const gfx::Rect& bounds) {
|
||||
const gfx::Rect& bounds) const {
|
||||
if (!has_frame())
|
||||
return bounds;
|
||||
|
||||
|
@ -1201,7 +1204,7 @@ gfx::Rect NativeWindowViews::ContentBoundsToWindowBounds(
|
|||
}
|
||||
|
||||
gfx::Rect NativeWindowViews::WindowBoundsToContentBounds(
|
||||
const gfx::Rect& bounds) {
|
||||
const gfx::Rect& bounds) const {
|
||||
if (!has_frame())
|
||||
return bounds;
|
||||
|
||||
|
@ -1269,6 +1272,26 @@ void NativeWindowViews::HandleKeyboardEvent(
|
|||
}
|
||||
}
|
||||
|
||||
void NativeWindowViews::ShowAutofillPopup(
|
||||
content::RenderFrameHost* frame_host,
|
||||
const gfx::RectF& bounds,
|
||||
const std::vector<base::string16>& values,
|
||||
const std::vector<base::string16>& labels) {
|
||||
auto wc = atom::api::WebContents::FromWrappedClass(
|
||||
v8::Isolate::GetCurrent(), web_contents());
|
||||
autofill_popup_->CreateView(
|
||||
frame_host,
|
||||
wc->IsOffScreenOrEmbedderOffscreen(),
|
||||
widget(),
|
||||
bounds);
|
||||
autofill_popup_->SetItems(values, labels);
|
||||
}
|
||||
|
||||
void NativeWindowViews::HideAutofillPopup(
|
||||
content::RenderFrameHost* frame_host) {
|
||||
autofill_popup_->Hide();
|
||||
}
|
||||
|
||||
void NativeWindowViews::Layout() {
|
||||
const auto size = GetContentsBounds().size();
|
||||
const auto menu_bar_bounds =
|
||||
|
@ -1306,11 +1329,11 @@ void NativeWindowViews::Layout() {
|
|||
}
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowViews::GetMinimumSize() {
|
||||
gfx::Size NativeWindowViews::GetMinimumSize() const {
|
||||
return NativeWindow::GetMinimumSize();
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowViews::GetMaximumSize() {
|
||||
gfx::Size NativeWindowViews::GetMaximumSize() const {
|
||||
return NativeWindow::GetMaximumSize();
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "atom/browser/ui/accelerator_util.h"
|
||||
#include "atom/browser/ui/autofill_popup.h"
|
||||
#include "ui/views/widget/widget_delegate.h"
|
||||
#include "ui/views/widget/widget_observer.h"
|
||||
|
||||
|
@ -106,8 +107,8 @@ class NativeWindowViews : public NativeWindow,
|
|||
void SetMenu(AtomMenuModel* menu_model) override;
|
||||
void SetBrowserView(NativeBrowserView* browser_view) override;
|
||||
void SetParentWindow(NativeWindow* parent) override;
|
||||
gfx::NativeView GetNativeView() override;
|
||||
gfx::NativeWindow GetNativeWindow() override;
|
||||
gfx::NativeView GetNativeView() const override;
|
||||
gfx::NativeWindow GetNativeWindow() const override;
|
||||
void SetOverlayIcon(const gfx::Image& overlay,
|
||||
const std::string& description) override;
|
||||
void SetProgressBar(double progress, const ProgressState state) override;
|
||||
|
@ -118,7 +119,7 @@ class NativeWindowViews : public NativeWindow,
|
|||
void SetVisibleOnAllWorkspaces(bool visible) override;
|
||||
bool IsVisibleOnAllWorkspaces() override;
|
||||
|
||||
gfx::AcceleratedWidget GetAcceleratedWidget() override;
|
||||
gfx::AcceleratedWidget GetAcceleratedWidget() const override;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
void SetIcon(HICON small_icon, HICON app_icon);
|
||||
|
@ -171,16 +172,22 @@ class NativeWindowViews : public NativeWindow,
|
|||
#endif
|
||||
|
||||
// NativeWindow:
|
||||
gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) override;
|
||||
gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) override;
|
||||
gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) const override;
|
||||
gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) const override;
|
||||
void HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) override;
|
||||
void ShowAutofillPopup(
|
||||
content::RenderFrameHost* frame_host,
|
||||
const gfx::RectF& bounds,
|
||||
const std::vector<base::string16>& values,
|
||||
const std::vector<base::string16>& labels) override;
|
||||
void HideAutofillPopup(content::RenderFrameHost* frame_host) override;
|
||||
|
||||
// views::View:
|
||||
void Layout() override;
|
||||
gfx::Size GetMinimumSize() override;
|
||||
gfx::Size GetMaximumSize() override;
|
||||
gfx::Size GetMinimumSize() const override;
|
||||
gfx::Size GetMaximumSize() const override;
|
||||
bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
|
||||
|
||||
// Register accelerators supported by the menu model.
|
||||
|
@ -194,6 +201,8 @@ class NativeWindowViews : public NativeWindow,
|
|||
|
||||
NativeBrowserView* browser_view_;
|
||||
|
||||
std::unique_ptr<AutofillPopup> autofill_popup_;
|
||||
|
||||
std::unique_ptr<MenuBar> menu_bar_;
|
||||
bool menu_bar_autohide_;
|
||||
bool menu_bar_visible_;
|
||||
|
|
|
@ -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_;
|
||||
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<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 (size_t i = 0; i < damages.size(); i++) {
|
||||
CopyBitmapTo(bitmap, *(bitmaps[i]), damages[i]);
|
||||
}
|
||||
|
||||
damage.Intersect(GetViewBounds());
|
||||
callback_.Run(damage, bitmap);
|
||||
|
||||
for (size_t 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)) {
|
||||
|
|
|
@ -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
atom/browser/osr/osr_view_proxy.cc
Normal file
58
atom/browser/osr/osr_view_proxy.cc
Normal 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
|
53
atom/browser/osr/osr_view_proxy.h
Normal file
53
atom/browser/osr/osr_view_proxy.h
Normal 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_
|
266
atom/browser/ui/autofill_popup.cc
Normal file
266
atom/browser/ui/autofill_popup.cc
Normal file
|
@ -0,0 +1,266 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <algorithm>
|
||||
#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"
|
||||
#include "ui/display/screen.h"
|
||||
#include "ui/gfx/geometry/point.h"
|
||||
#include "ui/gfx/geometry/rect.h"
|
||||
#include "ui/gfx/geometry/vector2d.h"
|
||||
#include "ui/gfx/text_utils.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
std::pair<int, int> CalculatePopupXAndWidth(
|
||||
const display::Display& left_display,
|
||||
const display::Display& right_display,
|
||||
int popup_required_width,
|
||||
const gfx::Rect& element_bounds,
|
||||
bool is_rtl) {
|
||||
int leftmost_display_x = left_display.bounds().x();
|
||||
int rightmost_display_x =
|
||||
right_display.GetSizeInPixel().width() + right_display.bounds().x();
|
||||
|
||||
// Calculate the start coordinates for the popup if it is growing right or
|
||||
// the end position if it is growing to the left, capped to screen space.
|
||||
int right_growth_start = std::max(
|
||||
leftmost_display_x, std::min(rightmost_display_x, element_bounds.x()));
|
||||
int left_growth_end =
|
||||
std::max(leftmost_display_x,
|
||||
std::min(rightmost_display_x, element_bounds.right()));
|
||||
|
||||
int right_available = rightmost_display_x - right_growth_start;
|
||||
int left_available = left_growth_end - leftmost_display_x;
|
||||
|
||||
int popup_width =
|
||||
std::min(popup_required_width, std::max(right_available, left_available));
|
||||
|
||||
std::pair<int, int> grow_right(right_growth_start, popup_width);
|
||||
std::pair<int, int> grow_left(left_growth_end - popup_width, popup_width);
|
||||
|
||||
// Prefer to grow towards the end (right for LTR, left for RTL). But if there
|
||||
// is not enough space available in the desired direction and more space in
|
||||
// the other direction, reverse it.
|
||||
if (is_rtl) {
|
||||
return left_available >= popup_width || left_available >= right_available
|
||||
? grow_left
|
||||
: grow_right;
|
||||
}
|
||||
return right_available >= popup_width || right_available >= left_available
|
||||
? grow_right
|
||||
: grow_left;
|
||||
}
|
||||
|
||||
std::pair<int, int> CalculatePopupYAndHeight(
|
||||
const display::Display& top_display,
|
||||
const display::Display& bottom_display,
|
||||
int popup_required_height,
|
||||
const gfx::Rect& element_bounds) {
|
||||
int topmost_display_y = top_display.bounds().y();
|
||||
int bottommost_display_y =
|
||||
bottom_display.GetSizeInPixel().height() + bottom_display.bounds().y();
|
||||
|
||||
// Calculate the start coordinates for the popup if it is growing down or
|
||||
// the end position if it is growing up, capped to screen space.
|
||||
int top_growth_end = std::max(
|
||||
topmost_display_y, std::min(bottommost_display_y, element_bounds.y()));
|
||||
int bottom_growth_start =
|
||||
std::max(topmost_display_y,
|
||||
std::min(bottommost_display_y, element_bounds.bottom()));
|
||||
|
||||
int top_available = bottom_growth_start - topmost_display_y;
|
||||
int bottom_available = bottommost_display_y - top_growth_end;
|
||||
|
||||
// TODO(csharp): Restrict the popup height to what is available.
|
||||
if (bottom_available >= popup_required_height ||
|
||||
bottom_available >= top_available) {
|
||||
// The popup can appear below the field.
|
||||
return std::make_pair(bottom_growth_start, popup_required_height);
|
||||
} else {
|
||||
// The popup must appear above the field.
|
||||
return std::make_pair(top_growth_end - popup_required_height,
|
||||
popup_required_height);
|
||||
}
|
||||
}
|
||||
|
||||
display::Display GetDisplayNearestPoint(
|
||||
const gfx::Point& point,
|
||||
gfx::NativeView container_view) {
|
||||
return display::Screen::GetScreen()->GetDisplayNearestPoint(point);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AutofillPopup::AutofillPopup(gfx::NativeView container_view)
|
||||
: container_view_(container_view), view_(nullptr) {
|
||||
bold_font_list_ =
|
||||
gfx::FontList().DeriveWithWeight(gfx::Font::Weight::BOLD);
|
||||
smaller_font_list_ =
|
||||
gfx::FontList().DeriveWithSizeDelta(kSmallerFontSizeDelta);
|
||||
}
|
||||
|
||||
AutofillPopup::~AutofillPopup() {
|
||||
Hide();
|
||||
}
|
||||
|
||||
void AutofillPopup::CreateView(
|
||||
content::RenderFrameHost* frame_host,
|
||||
bool offscreen,
|
||||
views::Widget* parent_widget,
|
||||
const gfx::RectF& r) {
|
||||
frame_host_ = frame_host;
|
||||
gfx::Rect lb(std::floor(r.x()), std::floor(r.y() + r.height()),
|
||||
std::floor(r.width()), std::floor(r.height()));
|
||||
gfx::Point menu_position(lb.origin());
|
||||
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_;
|
||||
|
||||
Hide();
|
||||
view_ = new AutofillPopupView(this, parent_widget);
|
||||
view_->Show();
|
||||
|
||||
if (offscreen) {
|
||||
auto* osr_rwhv = static_cast<OffScreenRenderWidgetHostView*>(
|
||||
frame_host_->GetView());
|
||||
view_->view_proxy_.reset(new OffscreenViewProxy(view_));
|
||||
osr_rwhv->AddViewProxy(view_->view_proxy_.get());
|
||||
}
|
||||
}
|
||||
|
||||
void AutofillPopup::Hide() {
|
||||
if (view_) {
|
||||
view_->Hide();
|
||||
view_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void AutofillPopup::SetItems(const std::vector<base::string16>& values,
|
||||
const std::vector<base::string16>& labels) {
|
||||
values_ = values;
|
||||
labels_ = labels;
|
||||
UpdatePopupBounds();
|
||||
if (view_) {
|
||||
view_->OnSuggestionsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void AutofillPopup::AcceptSuggestion(int index) {
|
||||
frame_host_->Send(new AtomAutofillFrameMsg_AcceptSuggestion(
|
||||
frame_host_->GetRoutingID(), GetValueAt(index)));
|
||||
}
|
||||
|
||||
void AutofillPopup::UpdatePopupBounds() {
|
||||
int desired_width = GetDesiredPopupWidth();
|
||||
int desired_height = GetDesiredPopupHeight();
|
||||
bool is_rtl = false;
|
||||
|
||||
gfx::Point top_left_corner_of_popup =
|
||||
element_bounds_.origin() +
|
||||
gfx::Vector2d(element_bounds_.width() - desired_width, -desired_height);
|
||||
|
||||
// This is the bottom right point of the popup if the popup is below the
|
||||
// element and grows to the right (since the is the lowest and furthest right
|
||||
// the popup could go).
|
||||
gfx::Point bottom_right_corner_of_popup =
|
||||
element_bounds_.origin() +
|
||||
gfx::Vector2d(desired_width, element_bounds_.height() + desired_height);
|
||||
|
||||
display::Display top_left_display =
|
||||
GetDisplayNearestPoint(top_left_corner_of_popup, container_view_);
|
||||
display::Display bottom_right_display =
|
||||
GetDisplayNearestPoint(bottom_right_corner_of_popup, container_view_);
|
||||
|
||||
std::pair<int, int> popup_x_and_width =
|
||||
CalculatePopupXAndWidth(top_left_display, bottom_right_display,
|
||||
desired_width, element_bounds_, is_rtl);
|
||||
std::pair<int, int> popup_y_and_height = CalculatePopupYAndHeight(
|
||||
top_left_display, bottom_right_display, desired_height, element_bounds_);
|
||||
|
||||
popup_bounds_ = gfx::Rect(popup_x_and_width.first, popup_y_and_height.first,
|
||||
popup_x_and_width.second, popup_y_and_height.second);
|
||||
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() {
|
||||
return 2 * kPopupBorderThickness + values_.size() * kRowHeight;
|
||||
}
|
||||
|
||||
int AutofillPopup::GetDesiredPopupWidth() {
|
||||
int popup_width = element_bounds_.width();
|
||||
|
||||
for (size_t i = 0; i < values_.size(); ++i) {
|
||||
int row_size = kEndPadding + 2 * kPopupBorderThickness +
|
||||
gfx::GetStringWidth(GetValueAt(i), GetValueFontListForRow(i)) +
|
||||
gfx::GetStringWidth(GetLabelAt(i), GetLabelFontListForRow(i));
|
||||
if (GetLabelAt(i).length() > 0)
|
||||
row_size += kNamePadding + kEndPadding;
|
||||
|
||||
popup_width = std::max(popup_width, row_size);
|
||||
}
|
||||
|
||||
return popup_width;
|
||||
}
|
||||
|
||||
gfx::Rect AutofillPopup::GetRowBounds(int index) {
|
||||
int top = kPopupBorderThickness + index * kRowHeight;
|
||||
|
||||
return gfx::Rect(kPopupBorderThickness, top,
|
||||
popup_bounds_.width() - 2 * kPopupBorderThickness,
|
||||
kRowHeight);
|
||||
}
|
||||
|
||||
const gfx::FontList& AutofillPopup::GetValueFontListForRow(int index) const {
|
||||
return bold_font_list_;
|
||||
}
|
||||
|
||||
const gfx::FontList& AutofillPopup::GetLabelFontListForRow(int index) const {
|
||||
return smaller_font_list_;
|
||||
}
|
||||
|
||||
ui::NativeTheme::ColorId AutofillPopup::GetBackgroundColorIDForRow(
|
||||
int index) const {
|
||||
return (view_ && index == view_->GetSelectedLine())
|
||||
? ui::NativeTheme::kColorId_ResultsTableHoveredBackground
|
||||
: ui::NativeTheme::kColorId_ResultsTableNormalBackground;
|
||||
}
|
||||
|
||||
int AutofillPopup::GetLineCount() {
|
||||
return values_.size();
|
||||
}
|
||||
|
||||
base::string16 AutofillPopup::GetValueAt(int i) {
|
||||
return values_.at(i);
|
||||
}
|
||||
|
||||
base::string16 AutofillPopup::GetLabelAt(int i) {
|
||||
return labels_.at(i);
|
||||
}
|
||||
|
||||
int AutofillPopup::LineFromY(int y) const {
|
||||
int current_height = kPopupBorderThickness;
|
||||
|
||||
for (size_t i = 0; i < values_.size(); ++i) {
|
||||
current_height += kRowHeight;
|
||||
|
||||
if (y <= current_height)
|
||||
return i;
|
||||
}
|
||||
|
||||
return values_.size() - 1;
|
||||
}
|
||||
|
||||
} // namespace atom
|
82
atom/browser/ui/autofill_popup.h
Normal file
82
atom/browser/ui/autofill_popup.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_UI_AUTOFILL_POPUP_H_
|
||||
#define ATOM_BROWSER_UI_AUTOFILL_POPUP_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/ui/views/autofill_popup_view.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "ui/gfx/font_list.h"
|
||||
#include "ui/native_theme/native_theme.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AutofillPopupView;
|
||||
|
||||
class AutofillPopup {
|
||||
public:
|
||||
explicit AutofillPopup(gfx::NativeView);
|
||||
~AutofillPopup();
|
||||
|
||||
void CreateView(content::RenderFrameHost* render_frame,
|
||||
bool offscreen, views::Widget* widget, const gfx::RectF& bounds);
|
||||
void Hide();
|
||||
|
||||
void SetItems(const std::vector<base::string16>& values,
|
||||
const std::vector<base::string16>& labels);
|
||||
|
||||
private:
|
||||
friend class AutofillPopupView;
|
||||
|
||||
void AcceptSuggestion(int index);
|
||||
|
||||
void UpdatePopupBounds();
|
||||
int GetDesiredPopupHeight();
|
||||
int GetDesiredPopupWidth();
|
||||
gfx::Rect GetRowBounds(int i);
|
||||
const gfx::FontList& GetValueFontListForRow(int index) const;
|
||||
const gfx::FontList& GetLabelFontListForRow(int index) const;
|
||||
ui::NativeTheme::ColorId GetBackgroundColorIDForRow(int index) const;
|
||||
|
||||
int GetLineCount();
|
||||
base::string16 GetValueAt(int i);
|
||||
base::string16 GetLabelAt(int i);
|
||||
int LineFromY(int y) const;
|
||||
|
||||
// The native view that contains this
|
||||
gfx::NativeView container_view_;
|
||||
|
||||
int selected_index_;
|
||||
|
||||
// Popup location
|
||||
gfx::Rect popup_bounds_;
|
||||
gfx::Rect popup_bounds_in_view_;
|
||||
|
||||
// Bounds of the autofilled element
|
||||
gfx::Rect element_bounds_;
|
||||
|
||||
// Datalist suggestions
|
||||
std::vector<base::string16> values_;
|
||||
std::vector<base::string16> labels_;
|
||||
|
||||
// Font lists for the suggestions
|
||||
gfx::FontList smaller_font_list_;
|
||||
gfx::FontList bold_font_list_;
|
||||
|
||||
// For sending the accepted suggestion to the render frame that
|
||||
// asked to open the popup
|
||||
content::RenderFrameHost* frame_host_;
|
||||
|
||||
// The popup view. The lifetime is managed by the owning Widget
|
||||
AutofillPopupView* view_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AutofillPopup);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_UI_AUTOFILL_POPUP_H_
|
471
atom/browser/ui/views/autofill_popup_view.cc
Normal file
471
atom/browser/ui/views/autofill_popup_view.cc
Normal file
|
@ -0,0 +1,471 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/ui/views/autofill_popup_view.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/i18n/rtl.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "ui/events/keycodes/keyboard_codes.h"
|
||||
#include "ui/gfx/canvas.h"
|
||||
#include "ui/gfx/geometry/point.h"
|
||||
#include "ui/gfx/geometry/rect.h"
|
||||
#include "ui/gfx/text_utils.h"
|
||||
#include "ui/views/border.h"
|
||||
#include "ui/views/focus/focus_manager.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
AutofillPopupView::AutofillPopupView(
|
||||
AutofillPopup* popup,
|
||||
views::Widget* parent_widget)
|
||||
: popup_(popup),
|
||||
parent_widget_(parent_widget),
|
||||
view_proxy_(nullptr),
|
||||
weak_ptr_factory_(this) {
|
||||
CreateChildViews();
|
||||
SetFocusBehavior(FocusBehavior::ALWAYS);
|
||||
set_drag_controller(this);
|
||||
}
|
||||
|
||||
AutofillPopupView::~AutofillPopupView() {
|
||||
if (popup_) {
|
||||
auto host = popup_->frame_host_->GetRenderViewHost()->GetWidget();
|
||||
host->RemoveKeyPressEventCallback(keypress_callback_);
|
||||
popup_->view_ = nullptr;
|
||||
popup_ = nullptr;
|
||||
}
|
||||
|
||||
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);
|
||||
views::FocusManager* focus_manager = parent_widget_->GetFocusManager();
|
||||
focus_manager->RegisterAccelerator(
|
||||
ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE),
|
||||
ui::AcceleratorManager::kNormalPriority,
|
||||
this);
|
||||
focus_manager->RegisterAccelerator(
|
||||
ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE),
|
||||
ui::AcceleratorManager::kNormalPriority,
|
||||
this);
|
||||
|
||||
// The widget is destroyed by the corresponding NativeWidget, so we use
|
||||
// a weak pointer to hold the reference and don't have to worry about
|
||||
// deletion.
|
||||
views::Widget* widget = new views::Widget;
|
||||
views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
|
||||
params.delegate = this;
|
||||
params.parent = parent_widget_->GetNativeView();
|
||||
widget->Init(params);
|
||||
|
||||
// No animation for popup appearance (too distracting).
|
||||
widget->SetVisibilityAnimationTransition(views::Widget::ANIMATE_HIDE);
|
||||
|
||||
show_time_ = base::Time::Now();
|
||||
}
|
||||
|
||||
SetBorder(views::CreateSolidBorder(
|
||||
kPopupBorderThickness,
|
||||
GetNativeTheme()->GetSystemColor(
|
||||
ui::NativeTheme::kColorId_UnfocusedBorderColor)));
|
||||
|
||||
DoUpdateBoundsAndRedrawPopup();
|
||||
GetWidget()->Show();
|
||||
|
||||
if (initialize_widget)
|
||||
views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this);
|
||||
|
||||
keypress_callback_ = base::Bind(&AutofillPopupView::HandleKeyPressEvent,
|
||||
base::Unretained(this));
|
||||
auto host = popup_->frame_host_->GetRenderViewHost()->GetWidget();
|
||||
host->AddKeyPressEventCallback(keypress_callback_);
|
||||
|
||||
NotifyAccessibilityEvent(ui::AX_EVENT_MENU_START, true);
|
||||
}
|
||||
|
||||
void AutofillPopupView::Hide() {
|
||||
if (popup_) {
|
||||
auto host = popup_->frame_host_->GetRenderViewHost()->GetWidget();
|
||||
host->RemoveKeyPressEventCallback(keypress_callback_);
|
||||
popup_ = nullptr;
|
||||
}
|
||||
|
||||
RemoveObserver();
|
||||
NotifyAccessibilityEvent(ui::AX_EVENT_MENU_END, true);
|
||||
|
||||
if (GetWidget()) {
|
||||
GetWidget()->Close();
|
||||
}
|
||||
}
|
||||
|
||||
void AutofillPopupView::OnSuggestionsChanged() {
|
||||
if (!popup_)
|
||||
return;
|
||||
|
||||
CreateChildViews();
|
||||
if (popup_->GetLineCount() == 0) {
|
||||
popup_->Hide();
|
||||
return;
|
||||
}
|
||||
DoUpdateBoundsAndRedrawPopup();
|
||||
}
|
||||
|
||||
void AutofillPopupView::OnSelectedRowChanged(
|
||||
base::Optional<int> previous_row_selection,
|
||||
base::Optional<int> current_row_selection) {
|
||||
SchedulePaint();
|
||||
|
||||
if (current_row_selection) {
|
||||
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 = 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;
|
||||
value_rect.Inset(kEndPadding, 0);
|
||||
|
||||
int x_align_left = value_rect.x();
|
||||
const int value_width = gfx::GetStringWidth(
|
||||
popup_->GetValueAt(index),
|
||||
popup_->GetValueFontListForRow(index));
|
||||
int value_x_align_left = x_align_left;
|
||||
value_x_align_left =
|
||||
is_rtl ? value_rect.right() - value_width : value_rect.x();
|
||||
|
||||
canvas->DrawStringRectWithFlags(
|
||||
popup_->GetValueAt(index),
|
||||
popup_->GetValueFontListForRow(index),
|
||||
GetNativeTheme()->GetSystemColor(
|
||||
ui::NativeTheme::kColorId_ResultsTableNormalText),
|
||||
gfx::Rect(value_x_align_left, value_rect.y(), value_width,
|
||||
value_rect.height()),
|
||||
text_align);
|
||||
|
||||
// Draw the label text, if one exists.
|
||||
if (!popup_->GetLabelAt(index).empty()) {
|
||||
const int label_width = gfx::GetStringWidth(
|
||||
popup_->GetLabelAt(index),
|
||||
popup_->GetLabelFontListForRow(index));
|
||||
int label_x_align_left = x_align_left;
|
||||
label_x_align_left =
|
||||
is_rtl ? value_rect.x() : value_rect.right() - label_width;
|
||||
|
||||
canvas->DrawStringRectWithFlags(
|
||||
popup_->GetLabelAt(index),
|
||||
popup_->GetLabelFontListForRow(index),
|
||||
GetNativeTheme()->GetSystemColor(
|
||||
ui::NativeTheme::kColorId_ResultsTableNormalDimmedText),
|
||||
gfx::Rect(label_x_align_left, entry_rect.y(), label_width,
|
||||
entry_rect.height()),
|
||||
text_align);
|
||||
}
|
||||
}
|
||||
|
||||
void AutofillPopupView::CreateChildViews() {
|
||||
if (!popup_)
|
||||
return;
|
||||
|
||||
RemoveAllChildViews(true);
|
||||
|
||||
for (int i = 0; i < popup_->GetLineCount(); ++i) {
|
||||
auto child_view = new AutofillPopupChildView(popup_->GetValueAt(i));
|
||||
child_view->set_drag_controller(this);
|
||||
AddChildView(child_view);
|
||||
}
|
||||
}
|
||||
|
||||
void AutofillPopupView::DoUpdateBoundsAndRedrawPopup() {
|
||||
if (!popup_)
|
||||
return;
|
||||
|
||||
GetWidget()->SetBounds(popup_->popup_bounds_);
|
||||
SchedulePaint();
|
||||
}
|
||||
|
||||
void AutofillPopupView::OnPaint(gfx::Canvas* canvas) {
|
||||
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);
|
||||
}
|
||||
|
||||
draw_canvas->DrawColor(GetNativeTheme()->GetSystemColor(
|
||||
ui::NativeTheme::kColorId_ResultsTableNormalBackground));
|
||||
OnPaintBorder(draw_canvas);
|
||||
|
||||
for (int i = 0; i < popup_->GetLineCount(); ++i) {
|
||||
gfx::Rect line_rect = popup_->GetRowBounds(i);
|
||||
|
||||
DrawAutofillEntry(draw_canvas, i, line_rect);
|
||||
}
|
||||
|
||||
if (view_proxy_.get()) {
|
||||
view_proxy_->SetBounds(popup_->popup_bounds_in_view_);
|
||||
view_proxy_->SetBitmap(bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
void AutofillPopupView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
|
||||
node_data->role = ui::AX_ROLE_MENU;
|
||||
node_data->SetName("Autofill Menu");
|
||||
}
|
||||
|
||||
void AutofillPopupView::OnMouseCaptureLost() {
|
||||
ClearSelection();
|
||||
}
|
||||
|
||||
bool AutofillPopupView::OnMouseDragged(const ui::MouseEvent& event) {
|
||||
if (HitTestPoint(event.location())) {
|
||||
SetSelection(event.location());
|
||||
|
||||
// We must return true in order to get future OnMouseDragged and
|
||||
// OnMouseReleased events.
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we move off of the popup, we lose the selection.
|
||||
ClearSelection();
|
||||
return false;
|
||||
}
|
||||
|
||||
void AutofillPopupView::OnMouseExited(const ui::MouseEvent& event) {
|
||||
// Pressing return causes the cursor to hide, which will generate an
|
||||
// OnMouseExited event. Pressing return should activate the current selection
|
||||
// via AcceleratorPressed, so we need to let that run first.
|
||||
base::ThreadTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE, base::Bind(&AutofillPopupView::ClearSelection,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
void AutofillPopupView::OnMouseMoved(const ui::MouseEvent& event) {
|
||||
// A synthesized mouse move will be sent when the popup is first shown.
|
||||
// Don't preview a suggestion if the mouse happens to be hovering there.
|
||||
#if defined(OS_WIN)
|
||||
if (base::Time::Now() - show_time_ <= base::TimeDelta::FromMilliseconds(50))
|
||||
return;
|
||||
#else
|
||||
if (event.flags() & ui::EF_IS_SYNTHESIZED)
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (HitTestPoint(event.location()))
|
||||
SetSelection(event.location());
|
||||
else
|
||||
ClearSelection();
|
||||
}
|
||||
|
||||
bool AutofillPopupView::OnMousePressed(const ui::MouseEvent& event) {
|
||||
return event.GetClickCount() == 1;
|
||||
}
|
||||
|
||||
void AutofillPopupView::OnMouseReleased(const ui::MouseEvent& event) {
|
||||
// We only care about the left click.
|
||||
if (event.IsOnlyLeftMouseButton() && HitTestPoint(event.location()))
|
||||
AcceptSelection(event.location());
|
||||
}
|
||||
|
||||
void AutofillPopupView::OnGestureEvent(ui::GestureEvent* event) {
|
||||
switch (event->type()) {
|
||||
case ui::ET_GESTURE_TAP_DOWN:
|
||||
case ui::ET_GESTURE_SCROLL_BEGIN:
|
||||
case ui::ET_GESTURE_SCROLL_UPDATE:
|
||||
if (HitTestPoint(event->location()))
|
||||
SetSelection(event->location());
|
||||
else
|
||||
ClearSelection();
|
||||
break;
|
||||
case ui::ET_GESTURE_TAP:
|
||||
case ui::ET_GESTURE_SCROLL_END:
|
||||
if (HitTestPoint(event->location()))
|
||||
AcceptSelection(event->location());
|
||||
else
|
||||
ClearSelection();
|
||||
break;
|
||||
case ui::ET_GESTURE_TAP_CANCEL:
|
||||
case ui::ET_SCROLL_FLING_START:
|
||||
ClearSelection();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
event->SetHandled();
|
||||
}
|
||||
|
||||
bool AutofillPopupView::AcceleratorPressed(
|
||||
const ui::Accelerator& accelerator) {
|
||||
if (accelerator.modifiers() != ui::EF_NONE)
|
||||
return false;
|
||||
|
||||
if (accelerator.key_code() == ui::VKEY_ESCAPE) {
|
||||
if (popup_)
|
||||
popup_->Hide();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (accelerator.key_code() == ui::VKEY_RETURN)
|
||||
return AcceptSelectedLine();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AutofillPopupView::HandleKeyPressEvent(
|
||||
const content::NativeWebKeyboardEvent& event) {
|
||||
if (!popup_)
|
||||
return false;
|
||||
switch (event.windowsKeyCode) {
|
||||
case ui::VKEY_UP:
|
||||
SelectPreviousLine();
|
||||
return true;
|
||||
case ui::VKEY_DOWN:
|
||||
SelectNextLine();
|
||||
return true;
|
||||
case ui::VKEY_PRIOR: // Page up.
|
||||
SetSelectedLine(0);
|
||||
return true;
|
||||
case ui::VKEY_NEXT: // Page down.
|
||||
SetSelectedLine(popup_->GetLineCount() - 1);
|
||||
return true;
|
||||
case ui::VKEY_ESCAPE:
|
||||
popup_->Hide();
|
||||
return true;
|
||||
case ui::VKEY_TAB:
|
||||
// A tab press should cause the selected line to be accepted, but still
|
||||
// return false so the tab key press propagates and changes the cursor
|
||||
// location.
|
||||
AcceptSelectedLine();
|
||||
return false;
|
||||
case ui::VKEY_RETURN:
|
||||
return AcceptSelectedLine();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void AutofillPopupView::OnNativeFocusChanged(gfx::NativeView focused_now) {
|
||||
if (GetWidget() && GetWidget()->GetNativeView() != focused_now && popup_)
|
||||
popup_->Hide();
|
||||
}
|
||||
|
||||
void AutofillPopupView::OnWidgetBoundsChanged(views::Widget* widget,
|
||||
const gfx::Rect& new_bounds) {
|
||||
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_ || selected_line_.value() >= popup_->GetLineCount())
|
||||
return false;
|
||||
|
||||
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 && selected_line.value() >= popup_->GetLineCount())
|
||||
return;
|
||||
|
||||
auto previous_selected_line(selected_line_);
|
||||
selected_line_ = selected_line;
|
||||
OnSelectedRowChanged(previous_selected_line, 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;
|
||||
|
||||
SetSelectedLine(new_selected_line);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
SetSelectedLine(new_selected_line);
|
||||
}
|
||||
|
||||
void AutofillPopupView::ClearSelection() {
|
||||
SetSelectedLine(base::nullopt);
|
||||
}
|
||||
|
||||
void AutofillPopupView::RemoveObserver() {
|
||||
parent_widget_->GetFocusManager()->UnregisterAccelerators(this);
|
||||
parent_widget_->RemoveObserver(this);
|
||||
views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this);
|
||||
}
|
||||
|
||||
} // namespace atom
|
152
atom/browser/ui/views/autofill_popup_view.h
Normal file
152
atom/browser/ui/views/autofill_popup_view.h
Normal file
|
@ -0,0 +1,152 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_UI_VIEWS_AUTOFILL_POPUP_VIEW_H_
|
||||
#define ATOM_BROWSER_UI_VIEWS_AUTOFILL_POPUP_VIEW_H_
|
||||
|
||||
#include "atom/browser/ui/autofill_popup.h"
|
||||
|
||||
#include "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"
|
||||
#include "ui/accessibility/ax_node_data.h"
|
||||
#include "ui/views/drag_controller.h"
|
||||
#include "ui/views/focus/widget_focus_manager.h"
|
||||
#include "ui/views/widget/widget_delegate.h"
|
||||
#include "ui/views/widget/widget_observer.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
const int kPopupBorderThickness = 1;
|
||||
const int kSmallerFontSizeDelta = -1;
|
||||
const int kEndPadding = 8;
|
||||
const int kNamePadding = 15;
|
||||
const int kRowHeight = 24;
|
||||
|
||||
class AutofillPopup;
|
||||
|
||||
// Child view only for triggering accessibility events. Rendering is handled
|
||||
// by |AutofillPopupViewViews|.
|
||||
class AutofillPopupChildView : public views::View {
|
||||
public:
|
||||
explicit AutofillPopupChildView(const base::string16& suggestion)
|
||||
: suggestion_(suggestion) {
|
||||
SetFocusBehavior(FocusBehavior::ALWAYS);
|
||||
}
|
||||
|
||||
private:
|
||||
~AutofillPopupChildView() override {}
|
||||
|
||||
// views::Views implementation
|
||||
void GetAccessibleNodeData(ui::AXNodeData* node_data) override {
|
||||
node_data->role = ui::AX_ROLE_MENU_ITEM;
|
||||
node_data->SetName(suggestion_);
|
||||
}
|
||||
|
||||
base::string16 suggestion_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AutofillPopupChildView);
|
||||
};
|
||||
|
||||
class AutofillPopupView : public views::WidgetDelegateView,
|
||||
public views::WidgetFocusChangeListener,
|
||||
public views::WidgetObserver,
|
||||
public views::DragController {
|
||||
public:
|
||||
explicit AutofillPopupView(AutofillPopup* popup,
|
||||
views::Widget* parent_widget);
|
||||
~AutofillPopupView() override;
|
||||
|
||||
void Show();
|
||||
void Hide();
|
||||
|
||||
void OnSuggestionsChanged();
|
||||
|
||||
int GetSelectedLine() { return selected_line_.value_or(-1); }
|
||||
|
||||
void WriteDragDataForView(
|
||||
views::View*, const gfx::Point&, ui::OSExchangeData*) override {}
|
||||
int GetDragOperationsForView(views::View*, const gfx::Point&) override {
|
||||
return ui::DragDropTypes::DRAG_NONE;
|
||||
}
|
||||
bool CanStartDragForView(
|
||||
views::View*, const gfx::Point&, const gfx::Point&) override {
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class AutofillPopup;
|
||||
|
||||
void OnSelectedRowChanged(base::Optional<int> previous_row_selection,
|
||||
base::Optional<int> current_row_selection);
|
||||
|
||||
// Draw the given autofill entry in |entry_rect|.
|
||||
void DrawAutofillEntry(gfx::Canvas* canvas,
|
||||
int index,
|
||||
const gfx::Rect& entry_rect);
|
||||
|
||||
// Creates child views based on the suggestions given by |controller_|. These
|
||||
// child views are used for accessibility events only. We need child views to
|
||||
// populate the correct |AXNodeData| when user selects a suggestion.
|
||||
void CreateChildViews();
|
||||
|
||||
void DoUpdateBoundsAndRedrawPopup();
|
||||
|
||||
// views::Views implementation.
|
||||
void OnPaint(gfx::Canvas* canvas) override;
|
||||
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
|
||||
void OnMouseCaptureLost() override;
|
||||
bool OnMouseDragged(const ui::MouseEvent& event) override;
|
||||
void OnMouseExited(const ui::MouseEvent& event) override;
|
||||
void OnMouseMoved(const ui::MouseEvent& event) override;
|
||||
bool OnMousePressed(const ui::MouseEvent& event) override;
|
||||
void OnMouseReleased(const ui::MouseEvent& event) override;
|
||||
void OnGestureEvent(ui::GestureEvent* event) override;
|
||||
bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
|
||||
bool HandleKeyPressEvent(const content::NativeWebKeyboardEvent& event);
|
||||
|
||||
// views::WidgetFocusChangeListener implementation.
|
||||
void OnNativeFocusChanged(gfx::NativeView focused_now) override;
|
||||
|
||||
// views::WidgetObserver implementation.
|
||||
void OnWidgetBoundsChanged(views::Widget* widget,
|
||||
const gfx::Rect& new_bounds) override;
|
||||
|
||||
void AcceptSuggestion(int index);
|
||||
bool AcceptSelectedLine();
|
||||
void AcceptSelection(const gfx::Point& point);
|
||||
void SetSelectedLine(base::Optional<int> selected_line);
|
||||
void SetSelection(const gfx::Point& point);
|
||||
void SelectNextLine();
|
||||
void SelectPreviousLine();
|
||||
void ClearSelection();
|
||||
|
||||
// Stop observing the widget.
|
||||
void RemoveObserver();
|
||||
|
||||
// Controller for this popup. Weak reference.
|
||||
AutofillPopup* popup_;
|
||||
|
||||
// The widget of the window that triggered this popup. Weak reference.
|
||||
views::Widget* parent_widget_;
|
||||
|
||||
// The time when the popup was shown.
|
||||
base::Time show_time_;
|
||||
|
||||
// The index of the currently selected line
|
||||
base::Optional<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_;
|
||||
|
||||
base::WeakPtrFactory<AutofillPopupView> weak_ptr_factory_;
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_UI_VIEWS_AUTOFILL_POPUP_VIEW_H_
|
|
@ -119,7 +119,7 @@ bool MenuBar::GetMenuButtonFromScreenPoint(const gfx::Point& point,
|
|||
|
||||
for (int i = 0; i < child_count(); ++i) {
|
||||
views::View* view = child_at(i);
|
||||
if (view->bounds().Contains(location) &&
|
||||
if (view->GetMirroredBounds().Contains(location) &&
|
||||
(menu_model_->GetTypeAt(i) == AtomMenuModel::TYPE_SUBMENU)) {
|
||||
*menu_model = menu_model_->GetSubmenuModelAt(i);
|
||||
*button = static_cast<views::MenuButton*>(view);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "base/values.h"
|
||||
#include "content/public/common/common_param_traits.h"
|
||||
#include "ipc/ipc_message_macros.h"
|
||||
#include "ui/gfx/geometry/rect_f.h"
|
||||
#include "ui/gfx/ipc/gfx_param_traits.h"
|
||||
|
||||
// The message starter should be declared in ipc/ipc_message_start.h. Since
|
||||
|
@ -37,6 +38,16 @@ IPC_MESSAGE_ROUTED3(AtomViewMsg_Message,
|
|||
|
||||
IPC_MESSAGE_ROUTED0(AtomViewMsg_Offscreen)
|
||||
|
||||
IPC_MESSAGE_ROUTED3(AtomAutofillFrameHostMsg_ShowPopup,
|
||||
gfx::RectF /* bounds */,
|
||||
std::vector<base::string16> /* values */,
|
||||
std::vector<base::string16> /* labels */)
|
||||
|
||||
IPC_MESSAGE_ROUTED0(AtomAutofillFrameHostMsg_HidePopup)
|
||||
|
||||
IPC_MESSAGE_ROUTED1(AtomAutofillFrameMsg_AcceptSuggestion,
|
||||
base::string16 /* suggestion */)
|
||||
|
||||
// Sent by the renderer when the draggable regions are updated.
|
||||
IPC_MESSAGE_ROUTED1(AtomViewHostMsg_UpdateDraggableRegions,
|
||||
std::vector<atom::DraggableRegion> /* regions */)
|
||||
|
|
233
atom/renderer/atom_autofill_agent.cc
Normal file
233
atom/renderer/atom_autofill_agent.cc
Normal file
|
@ -0,0 +1,233 @@
|
|||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/renderer/atom_autofill_agent.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "atom/common/api/api_messages.h"
|
||||
#include "content/public/renderer/render_frame.h"
|
||||
#include "content/public/renderer/render_view.h"
|
||||
#include "third_party/WebKit/public/platform/WebKeyboardEvent.h"
|
||||
#include "third_party/WebKit/public/platform/WebString.h"
|
||||
#include "third_party/WebKit/public/web/WebDocument.h"
|
||||
#include "third_party/WebKit/public/web/WebLocalFrame.h"
|
||||
#include "third_party/WebKit/public/web/WebOptionElement.h"
|
||||
#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
|
||||
#include "ui/events/keycodes/keyboard_codes.h"
|
||||
#include "ui/gfx/geometry/rect_f.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
const size_t kMaxDataLength = 1024;
|
||||
const size_t kMaxListSize = 512;
|
||||
|
||||
void GetDataListSuggestions(const blink::WebInputElement& element,
|
||||
std::vector<base::string16>* values,
|
||||
std::vector<base::string16>* labels) {
|
||||
for (const auto& option : element.filteredDataListOptions()) {
|
||||
values->push_back(option.value().utf16());
|
||||
if (option.value() != option.label())
|
||||
labels->push_back(option.label().utf16());
|
||||
else
|
||||
labels->push_back(base::string16());
|
||||
}
|
||||
}
|
||||
|
||||
void TrimStringVectorForIPC(std::vector<base::string16>* strings) {
|
||||
// Limit the size of the vector.
|
||||
if (strings->size() > kMaxListSize)
|
||||
strings->resize(kMaxListSize);
|
||||
|
||||
// Limit the size of the strings in the vector.
|
||||
for (size_t i = 0; i < strings->size(); ++i) {
|
||||
if ((*strings)[i].length() > kMaxDataLength)
|
||||
(*strings)[i].resize(kMaxDataLength);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
AutofillAgent::AutofillAgent(
|
||||
content::RenderFrame* frame)
|
||||
: content::RenderFrameObserver(frame),
|
||||
helper_(new Helper(this)),
|
||||
focused_node_was_last_clicked_(false),
|
||||
was_focused_before_now_(false),
|
||||
weak_ptr_factory_(this) {
|
||||
render_frame()->GetWebFrame()->setAutofillClient(this);
|
||||
}
|
||||
|
||||
void AutofillAgent::OnDestruct() {
|
||||
delete this;
|
||||
}
|
||||
|
||||
void AutofillAgent::DidChangeScrollOffset() {
|
||||
HidePopup();
|
||||
}
|
||||
|
||||
void AutofillAgent::FocusedNodeChanged(const blink::WebNode&) {
|
||||
focused_node_was_last_clicked_ = false;
|
||||
was_focused_before_now_ = false;
|
||||
HidePopup();
|
||||
}
|
||||
|
||||
void AutofillAgent::textFieldDidEndEditing(
|
||||
const blink::WebInputElement&) {
|
||||
HidePopup();
|
||||
}
|
||||
|
||||
void AutofillAgent::textFieldDidChange(
|
||||
const blink::WebFormControlElement& element) {
|
||||
if (!IsUserGesture() && !render_frame()->IsPasting())
|
||||
return;
|
||||
|
||||
weak_ptr_factory_.InvalidateWeakPtrs();
|
||||
base::ThreadTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE, base::Bind(&AutofillAgent::textFieldDidChangeImpl,
|
||||
weak_ptr_factory_.GetWeakPtr(), element));
|
||||
}
|
||||
|
||||
void AutofillAgent::textFieldDidChangeImpl(
|
||||
const blink::WebFormControlElement& element) {
|
||||
ShowSuggestionsOptions options;
|
||||
options.requires_caret_at_end = true;
|
||||
ShowSuggestions(element, options);
|
||||
}
|
||||
|
||||
void AutofillAgent::textFieldDidReceiveKeyDown(
|
||||
const blink::WebInputElement& element,
|
||||
const blink::WebKeyboardEvent& event) {
|
||||
if (event.windowsKeyCode == ui::VKEY_DOWN ||
|
||||
event.windowsKeyCode == ui::VKEY_UP) {
|
||||
ShowSuggestionsOptions options;
|
||||
options.autofill_on_empty_values = true;
|
||||
options.requires_caret_at_end = true;
|
||||
ShowSuggestions(element, options);
|
||||
}
|
||||
}
|
||||
|
||||
void AutofillAgent::openTextDataListChooser(
|
||||
const blink::WebInputElement& element) {
|
||||
ShowSuggestionsOptions options;
|
||||
options.autofill_on_empty_values = true;
|
||||
ShowSuggestions(element, options);
|
||||
}
|
||||
|
||||
void AutofillAgent::dataListOptionsChanged(
|
||||
const blink::WebInputElement& element) {
|
||||
if (!element.focused())
|
||||
return;
|
||||
|
||||
ShowSuggestionsOptions options;
|
||||
options.requires_caret_at_end = true;
|
||||
ShowSuggestions(element, options);
|
||||
}
|
||||
|
||||
AutofillAgent::ShowSuggestionsOptions::ShowSuggestionsOptions()
|
||||
: autofill_on_empty_values(false),
|
||||
requires_caret_at_end(false) {
|
||||
}
|
||||
|
||||
void AutofillAgent::ShowSuggestions(
|
||||
const blink::WebFormControlElement& element,
|
||||
const ShowSuggestionsOptions& options) {
|
||||
if (!element.isEnabled() || element.isReadOnly())
|
||||
return;
|
||||
const blink::WebInputElement* input_element = toWebInputElement(&element);
|
||||
if (input_element) {
|
||||
if (!input_element->isTextField())
|
||||
return;
|
||||
}
|
||||
|
||||
blink::WebString value = element.editingValue();
|
||||
if (value.length() > kMaxDataLength ||
|
||||
(!options.autofill_on_empty_values && value.isEmpty()) ||
|
||||
(options.requires_caret_at_end &&
|
||||
(element.selectionStart() != element.selectionEnd() ||
|
||||
element.selectionEnd() != static_cast<int>(value.length())))) {
|
||||
HidePopup();
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<base::string16> data_list_values;
|
||||
std::vector<base::string16> data_list_labels;
|
||||
if (input_element) {
|
||||
GetDataListSuggestions(
|
||||
*input_element, &data_list_values, &data_list_labels);
|
||||
TrimStringVectorForIPC(&data_list_values);
|
||||
TrimStringVectorForIPC(&data_list_labels);
|
||||
}
|
||||
|
||||
ShowPopup(element, data_list_values, data_list_labels);
|
||||
}
|
||||
|
||||
AutofillAgent::Helper::Helper(AutofillAgent* agent)
|
||||
: content::RenderViewObserver(agent->render_frame()->GetRenderView()),
|
||||
agent_(agent) {
|
||||
}
|
||||
|
||||
void AutofillAgent::Helper::OnMouseDown(const blink::WebNode& node) {
|
||||
agent_->focused_node_was_last_clicked_ = !node.isNull() && node.focused();
|
||||
}
|
||||
|
||||
void AutofillAgent::Helper::FocusChangeComplete() {
|
||||
agent_->DoFocusChangeComplete();
|
||||
}
|
||||
|
||||
bool AutofillAgent::OnMessageReceived(const IPC::Message& message) {
|
||||
bool handled = true;
|
||||
IPC_BEGIN_MESSAGE_MAP(AutofillAgent, message)
|
||||
IPC_MESSAGE_HANDLER(AtomAutofillFrameMsg_AcceptSuggestion,
|
||||
OnAcceptSuggestion)
|
||||
IPC_MESSAGE_UNHANDLED(handled = false)
|
||||
IPC_END_MESSAGE_MAP()
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
bool AutofillAgent::IsUserGesture() const {
|
||||
return blink::WebUserGestureIndicator::isProcessingUserGesture();
|
||||
}
|
||||
|
||||
void AutofillAgent::HidePopup() {
|
||||
Send(new AtomAutofillFrameHostMsg_HidePopup(render_frame()->GetRoutingID()));
|
||||
}
|
||||
|
||||
void AutofillAgent::ShowPopup(
|
||||
const blink::WebFormControlElement& element,
|
||||
const std::vector<base::string16>& values,
|
||||
const std::vector<base::string16>& labels) {
|
||||
gfx::RectF bounds =
|
||||
render_frame()->GetRenderView()->ElementBoundsInWindow(element);
|
||||
Send(new AtomAutofillFrameHostMsg_ShowPopup(
|
||||
render_frame()->GetRoutingID(), bounds, values, labels));
|
||||
}
|
||||
|
||||
void AutofillAgent::OnAcceptSuggestion(base::string16 suggestion) {
|
||||
auto element = render_frame()->GetWebFrame()->document().focusedElement();
|
||||
if (element.isFormControlElement()) {
|
||||
toWebInputElement(&element)->setSuggestedValue(
|
||||
blink::WebString::fromUTF16(suggestion));
|
||||
}
|
||||
}
|
||||
|
||||
void AutofillAgent::DoFocusChangeComplete() {
|
||||
auto element = render_frame()->GetWebFrame()->document().focusedElement();
|
||||
if (element.isNull() || !element.isFormControlElement())
|
||||
return;
|
||||
|
||||
if (focused_node_was_last_clicked_ && was_focused_before_now_) {
|
||||
ShowSuggestionsOptions options;
|
||||
options.autofill_on_empty_values = true;
|
||||
auto input_element = toWebInputElement(&element);
|
||||
if (input_element)
|
||||
ShowSuggestions(*input_element, options);
|
||||
}
|
||||
|
||||
was_focused_before_now_ = true;
|
||||
focused_node_was_last_clicked_ = false;
|
||||
}
|
||||
|
||||
} // namespace atom
|
91
atom/renderer/atom_autofill_agent.h
Normal file
91
atom/renderer/atom_autofill_agent.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_RENDERER_ATOM_AUTOFILL_AGENT_H_
|
||||
#define ATOM_RENDERER_ATOM_AUTOFILL_AGENT_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "content/public/renderer/render_frame_observer.h"
|
||||
#include "content/public/renderer/render_view_observer.h"
|
||||
#include "third_party/WebKit/public/web/WebAutofillClient.h"
|
||||
#include "third_party/WebKit/public/web/WebFormControlElement.h"
|
||||
#include "third_party/WebKit/public/web/WebInputElement.h"
|
||||
#include "third_party/WebKit/public/web/WebNode.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AutofillAgent : public content::RenderFrameObserver,
|
||||
public blink::WebAutofillClient {
|
||||
public:
|
||||
explicit AutofillAgent(content::RenderFrame* frame);
|
||||
|
||||
// content::RenderFrameObserver:
|
||||
void OnDestruct() override;
|
||||
|
||||
void DidChangeScrollOffset() override;
|
||||
void FocusedNodeChanged(const blink::WebNode&) override;
|
||||
|
||||
private:
|
||||
class Helper : public content::RenderViewObserver {
|
||||
public:
|
||||
explicit Helper(AutofillAgent* agent);
|
||||
|
||||
// content::RenderViewObserver implementation.
|
||||
void OnDestruct() override {}
|
||||
void OnMouseDown(const blink::WebNode&) override;
|
||||
void FocusChangeComplete() override;
|
||||
|
||||
private:
|
||||
AutofillAgent* agent_;
|
||||
};
|
||||
friend class Helper;
|
||||
|
||||
struct ShowSuggestionsOptions {
|
||||
ShowSuggestionsOptions();
|
||||
bool autofill_on_empty_values;
|
||||
bool requires_caret_at_end;
|
||||
};
|
||||
|
||||
bool OnMessageReceived(const IPC::Message& message) override;
|
||||
|
||||
// blink::WebAutofillClient:
|
||||
void textFieldDidEndEditing(const blink::WebInputElement&) override;
|
||||
void textFieldDidChange(const blink::WebFormControlElement&) override;
|
||||
void textFieldDidChangeImpl(const blink::WebFormControlElement&);
|
||||
void textFieldDidReceiveKeyDown(const blink::WebInputElement&,
|
||||
const blink::WebKeyboardEvent&) override;
|
||||
void openTextDataListChooser(const blink::WebInputElement&) override;
|
||||
void dataListOptionsChanged(const blink::WebInputElement&) override;
|
||||
|
||||
bool IsUserGesture() const;
|
||||
void HidePopup();
|
||||
void ShowPopup(const blink::WebFormControlElement&,
|
||||
const std::vector<base::string16>&,
|
||||
const std::vector<base::string16>&);
|
||||
void ShowSuggestions(const blink::WebFormControlElement& element,
|
||||
const ShowSuggestionsOptions& options);
|
||||
void OnAcceptSuggestion(base::string16 suggestion);
|
||||
|
||||
void DoFocusChangeComplete();
|
||||
|
||||
std::unique_ptr<Helper> helper_;
|
||||
|
||||
// True when the last click was on the focused node.
|
||||
bool focused_node_was_last_clicked_;
|
||||
|
||||
// This is set to false when the focus changes, then set back to true soon
|
||||
// afterwards. This helps track whether an event happened after a node was
|
||||
// already focused, or if it caused the focus to change.
|
||||
bool was_focused_before_now_;
|
||||
|
||||
base::WeakPtrFactory<AutofillAgent> weak_ptr_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AutofillAgent);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_RENDERER_ATOM_AUTOFILL_AGENT_H_
|
|
@ -11,6 +11,7 @@
|
|||
#include "atom/common/color_util.h"
|
||||
#include "atom/common/native_mate_converters/value_converter.h"
|
||||
#include "atom/common/options_switches.h"
|
||||
#include "atom/renderer/atom_autofill_agent.h"
|
||||
#include "atom/renderer/atom_render_frame_observer.h"
|
||||
#include "atom/renderer/content_settings_observer.h"
|
||||
#include "atom/renderer/guest_view_container.h"
|
||||
|
@ -120,6 +121,7 @@ void RendererClientBase::RenderThreadStarted() {
|
|||
void RendererClientBase::RenderFrameCreated(
|
||||
content::RenderFrame* render_frame) {
|
||||
new AtomRenderFrameObserver(render_frame, this);
|
||||
new AutofillAgent(render_frame);
|
||||
new PepperHelper(render_frame);
|
||||
new ContentSettingsObserver(render_frame);
|
||||
new printing::PrintWebViewHelper(render_frame);
|
||||
|
|
|
@ -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',
|
||||
|
@ -291,6 +293,8 @@
|
|||
'atom/browser/ui/accelerator_util_views.cc',
|
||||
'atom/browser/ui/atom_menu_model.cc',
|
||||
'atom/browser/ui/atom_menu_model.h',
|
||||
'atom/browser/ui/autofill_popup.cc',
|
||||
'atom/browser/ui/autofill_popup.h',
|
||||
'atom/browser/ui/certificate_trust.h',
|
||||
'atom/browser/ui/certificate_trust_mac.mm',
|
||||
'atom/browser/ui/certificate_trust_win.cc',
|
||||
|
@ -318,6 +322,8 @@
|
|||
'atom/browser/ui/tray_icon_cocoa.mm',
|
||||
'atom/browser/ui/tray_icon_observer.h',
|
||||
'atom/browser/ui/tray_icon_win.cc',
|
||||
'atom/browser/ui/views/autofill_popup_view.cc',
|
||||
'atom/browser/ui/views/autofill_popup_view.h',
|
||||
'atom/browser/ui/views/frameless_view.cc',
|
||||
'atom/browser/ui/views/frameless_view.h',
|
||||
'atom/browser/ui/views/global_menu_bar_x11.cc',
|
||||
|
@ -479,6 +485,8 @@
|
|||
'atom/renderer/api/atom_api_spell_check_client.h',
|
||||
'atom/renderer/api/atom_api_web_frame.cc',
|
||||
'atom/renderer/api/atom_api_web_frame.h',
|
||||
'atom/renderer/atom_autofill_agent.cc',
|
||||
'atom/renderer/atom_autofill_agent.h',
|
||||
'atom/renderer/atom_render_frame_observer.cc',
|
||||
'atom/renderer/atom_render_frame_observer.h',
|
||||
'atom/renderer/atom_render_view_observer.cc',
|
||||
|
|
Loading…
Reference in a new issue