blob: c7ef581e5719f69ca69aff0b3f3383a87f7bc30c [file] [log] [blame]
[email protected]6a8ddba52010-09-05 04:38:061// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/renderer/page_click_tracker.h"
6
[email protected]a22f7e02011-02-09 07:15:357#include "chrome/common/render_messages.h"
[email protected]6a8ddba52010-09-05 04:38:068#include "chrome/renderer/page_click_listener.h"
[email protected]55722152011-03-22 01:33:539#include "content/common/view_messages.h"
[email protected]60916042011-03-19 00:43:3610#include "content/renderer/render_view.h"
[email protected]8bd0fe62011-01-17 06:44:3711#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
12#include "third_party/WebKit/Source/WebKit/chromium/public/WebDOMMouseEvent.h"
13#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
14#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputElement.h"
15#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
16#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
[email protected]6a8ddba52010-09-05 04:38:0617
18using WebKit::WebDOMEvent;
19using WebKit::WebDOMMouseEvent;
20using WebKit::WebElement;
21using WebKit::WebFormControlElement;
22using WebKit::WebFrame;
23using WebKit::WebInputElement;
24using WebKit::WebInputEvent;
25using WebKit::WebMouseEvent;
26using WebKit::WebNode;
27using WebKit::WebString;
28using WebKit::WebView;
29
30PageClickTracker::PageClickTracker(RenderView* render_view)
[email protected]676126f72011-01-15 00:03:5131 : RenderViewObserver(render_view),
[email protected]6a8ddba52010-09-05 04:38:0632 was_focused_(false) {
33}
34
35PageClickTracker::~PageClickTracker() {
[email protected]676126f72011-01-15 00:03:5136 // Note that even though RenderView calls FrameDetached when notified that
[email protected]6a8ddba52010-09-05 04:38:0637 // a frame was closed, it might not always get that notification from WebKit
38 // for all frames.
39 // By the time we get here, the frame could have been destroyed so we cannot
40 // unregister listeners in frames remaining in tracked_frames_ as they might
41 // be invalid.
42}
43
[email protected]6a8ddba52010-09-05 04:38:0644void PageClickTracker::DidHandleMouseEvent(const WebMouseEvent& event) {
45 if (event.type != WebInputEvent::MouseDown ||
46 last_node_clicked_.isNull()) {
47 return;
48 }
49
50 // We are only interested in text field clicks.
51 if (!last_node_clicked_.isElementNode())
52 return;
53 const WebElement& element = last_node_clicked_.toConst<WebElement>();
54 if (!element.isFormControlElement())
55 return;
56 const WebFormControlElement& control =
57 element.toConst<WebFormControlElement>();
58 if (control.formControlType() != WebString::fromUTF8("text"))
59 return;
60
61 const WebInputElement& input_element = element.toConst<WebInputElement>();
62
63 bool is_focused = (last_node_clicked_ == GetFocusedNode());
64 ObserverListBase<PageClickListener>::Iterator it(listeners_);
65 PageClickListener* listener;
66 while ((listener = it.GetNext()) != NULL) {
67 if (listener->InputElementClicked(input_element, was_focused_, is_focused))
68 break;
69 }
70
71 last_node_clicked_.reset();
72}
73
74void PageClickTracker::AddListener(PageClickListener* listener) {
75 listeners_.AddObserver(listener);
76}
77
78void PageClickTracker::RemoveListener(PageClickListener* listener) {
79 listeners_.RemoveObserver(listener);
80}
81
[email protected]676126f72011-01-15 00:03:5182bool PageClickTracker::OnMessageReceived(const IPC::Message& message) {
83 if (message.type() == ViewMsg_HandleInputEvent::ID) {
84 void* iter = NULL;
85 const char* data;
86 int data_length;
87 if (message.ReadData(&iter, &data, &data_length)) {
88 const WebInputEvent* input_event =
89 reinterpret_cast<const WebInputEvent*>(data);
90 if (WebInputEvent::isMouseEventType(input_event->type))
91 DidHandleMouseEvent(*(static_cast<const WebMouseEvent*>(input_event)));
92 }
93 }
94 return false;
95}
96
97void PageClickTracker::DidFinishDocumentLoad(WebKit::WebFrame* frame) {
98 tracked_frames_.push_back(frame);
99 frame->document().addEventListener("mousedown", this, false);
100}
101
102void PageClickTracker::FrameDetached(WebKit::WebFrame* frame) {
103 FrameList::iterator iter =
104 std::find(tracked_frames_.begin(), tracked_frames_.end(), frame);
105 if (iter == tracked_frames_.end()) {
106 // Some frames might never load contents so we may not have a listener on
107 // them. Calling removeEventListener() on them would trigger an assert, so
108 // we need to keep track of which frames we are listening to.
109 return;
110 }
111 tracked_frames_.erase(iter);
112}
113
[email protected]6a8ddba52010-09-05 04:38:06114void PageClickTracker::handleEvent(const WebDOMEvent& event) {
115 last_node_clicked_.reset();
116
[email protected]1a5af2012010-10-29 22:46:29117 if (!event.isMouseEvent())
118 return;
119
[email protected]6a8ddba52010-09-05 04:38:06120 const WebDOMMouseEvent mouse_event = event.toConst<WebDOMMouseEvent>();
121 DCHECK(mouse_event.buttonDown());
122 if (mouse_event.button() != 0)
123 return; // We are only interested in left clicks.
124
125 // Remember which node has focus before the click is processed.
126 // We'll get a notification once the mouse event has been processed
127 // (DidHandleMouseEvent), we'll notify the listener at that point.
128 last_node_clicked_ = mouse_event.target();
129 was_focused_ = (GetFocusedNode() == last_node_clicked_);
130}
131
132WebNode PageClickTracker::GetFocusedNode() {
[email protected]676126f72011-01-15 00:03:51133 WebView* web_view = render_view()->webview();
[email protected]6a8ddba52010-09-05 04:38:06134 if (!web_view)
135 return WebNode();
136
137 WebFrame* web_frame = web_view->focusedFrame();
138 if (!web_frame)
139 return WebNode();
140
141 return web_frame->document().focusedNode();
142}