1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
|
// Copyright (c) 2011 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 "chrome/renderer/page_click_tracker.h"
#include "chrome/common/render_messages.h"
#include "chrome/renderer/page_click_listener.h"
#include "content/common/view_messages.h"
#include "content/renderer/render_view.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDOMMouseEvent.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputElement.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
using WebKit::WebDOMEvent;
using WebKit::WebDOMMouseEvent;
using WebKit::WebElement;
using WebKit::WebFormControlElement;
using WebKit::WebFrame;
using WebKit::WebInputElement;
using WebKit::WebInputEvent;
using WebKit::WebMouseEvent;
using WebKit::WebNode;
using WebKit::WebString;
using WebKit::WebView;
namespace {
// Casts |node| to a WebInputElement.
// Returns an empty (isNull()) WebInputElement if |node| is not a text
// WebInputElement.
const WebInputElement GetTextWebInputElement(const WebNode& node) {
if (!node.isElementNode())
return WebInputElement();
const WebElement element = node.toConst<WebElement>();
if (!element.isFormControlElement())
return WebInputElement();
const WebFormControlElement control =
element.toConst<WebFormControlElement>();
if (control.formControlType() != WebString::fromUTF8("text"))
return WebInputElement();
return element.toConst<WebInputElement>();
}
} // namespace
PageClickTracker::PageClickTracker(RenderView* render_view)
: RenderViewObserver(render_view),
was_focused_(false) {
}
PageClickTracker::~PageClickTracker() {
// Note that even though RenderView calls FrameDetached when notified that
// a frame was closed, it might not always get that notification from WebKit
// for all frames.
// By the time we get here, the frame could have been destroyed so we cannot
// unregister listeners in frames remaining in tracked_frames_ as they might
// be invalid.
}
void PageClickTracker::DidHandleMouseEvent(const WebMouseEvent& event) {
if (event.type != WebInputEvent::MouseDown ||
last_node_clicked_.isNull()) {
return;
}
// We are only interested in text field clicks.
const WebInputElement input_element =
GetTextWebInputElement(last_node_clicked_);
if (input_element.isNull())
return;
bool is_focused = (last_node_clicked_ == GetFocusedNode());
ObserverListBase<PageClickListener>::Iterator it(listeners_);
PageClickListener* listener;
while ((listener = it.GetNext()) != NULL) {
if (listener->InputElementClicked(input_element, was_focused_, is_focused))
break;
}
last_node_clicked_.reset();
}
void PageClickTracker::AddListener(PageClickListener* listener) {
listeners_.AddObserver(listener);
}
void PageClickTracker::RemoveListener(PageClickListener* listener) {
listeners_.RemoveObserver(listener);
}
bool PageClickTracker::OnMessageReceived(const IPC::Message& message) {
if (message.type() == ViewMsg_HandleInputEvent::ID) {
void* iter = NULL;
const char* data;
int data_length;
if (message.ReadData(&iter, &data, &data_length)) {
const WebInputEvent* input_event =
reinterpret_cast<const WebInputEvent*>(data);
if (WebInputEvent::isMouseEventType(input_event->type))
DidHandleMouseEvent(*(static_cast<const WebMouseEvent*>(input_event)));
}
}
return false;
}
void PageClickTracker::DidFinishDocumentLoad(WebKit::WebFrame* frame) {
tracked_frames_.push_back(frame);
frame->document().addEventListener("mousedown", this, false);
}
void PageClickTracker::FrameDetached(WebKit::WebFrame* frame) {
FrameList::iterator iter =
std::find(tracked_frames_.begin(), tracked_frames_.end(), frame);
if (iter == tracked_frames_.end()) {
// Some frames might never load contents so we may not have a listener on
// them. Calling removeEventListener() on them would trigger an assert, so
// we need to keep track of which frames we are listening to.
return;
}
tracked_frames_.erase(iter);
}
void PageClickTracker::handleEvent(const WebDOMEvent& event) {
last_node_clicked_.reset();
if (!event.isMouseEvent())
return;
const WebDOMMouseEvent mouse_event = event.toConst<WebDOMMouseEvent>();
DCHECK(mouse_event.buttonDown());
if (mouse_event.button() != 0)
return; // We are only interested in left clicks.
// Remember which node has focus before the click is processed.
// We'll get a notification once the mouse event has been processed
// (DidHandleMouseEvent), we'll notify the listener at that point.
WebNode node = mouse_event.target();
// We are only interested in text field clicks.
if (GetTextWebInputElement(node).isNull())
return;
last_node_clicked_ = node;
was_focused_ = (GetFocusedNode() == last_node_clicked_);
}
WebNode PageClickTracker::GetFocusedNode() {
WebView* web_view = render_view()->webview();
if (!web_view)
return WebNode();
WebFrame* web_frame = web_view->focusedFrame();
if (!web_frame)
return WebNode();
return web_frame->document().focusedNode();
}
|