diff options
author | jcivelli@chromium.org <jcivelli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-05 04:38:06 +0000 |
---|---|---|
committer | jcivelli@chromium.org <jcivelli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-05 04:38:06 +0000 |
commit | 6a8ddba5ea1e8972c2954b138aeb14d77a548a3c (patch) | |
tree | 4c1a21857eca96cea8a8743a28209041de389699 /chrome/renderer/page_click_tracker.cc | |
parent | e333e8d07ee32668fc132a21c13cdf674443d1e9 (diff) | |
download | chromium_src-6a8ddba5ea1e8972c2954b138aeb14d77a548a3c.zip chromium_src-6a8ddba5ea1e8972c2954b138aeb14d77a548a3c.tar.gz chromium_src-6a8ddba5ea1e8972c2954b138aeb14d77a548a3c.tar.bz2 |
Adding a class to track when a node in a page gets clicked.
This is going to be used by the password/form autofill to trigger the
suggestion popup, as part of the effort in moving that code out of WebKit.
BUG=None
TEST=Run unit-tests.
Review URL: http://codereview.chromium.org/3090007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@58597 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer/page_click_tracker.cc')
-rw-r--r-- | chrome/renderer/page_click_tracker.cc | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/chrome/renderer/page_click_tracker.cc b/chrome/renderer/page_click_tracker.cc new file mode 100644 index 0000000..e059bd3 --- /dev/null +++ b/chrome/renderer/page_click_tracker.cc @@ -0,0 +1,127 @@ +// Copyright (c) 2010 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/renderer/page_click_listener.h" +#include "chrome/renderer/render_view.h" +#include "third_party/WebKit/WebKit/chromium/public/WebDocument.h" +#include "third_party/WebKit/WebKit/chromium/public/WebDOMMouseEvent.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/WebKit/chromium/public/WebInputElement.h" +#include "third_party/WebKit/WebKit/chromium/public/WebString.h" +#include "third_party/WebKit/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; + +PageClickTracker::PageClickTracker(RenderView* render_view) + : render_view_(render_view), + was_focused_(false) { +} + +PageClickTracker::~PageClickTracker() { + // Note that even though RenderView calls StopTrackingFrame 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::StartTrackingFrame(WebFrame* frame) { + tracked_frames_.push_back(frame); + frame->document().addEventListener("mousedown", this, false); +} + +void PageClickTracker::StopTrackingFrame(WebFrame* frame, bool frame_detached) { + 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); + // If the frame has been detached, all event listeners have already been + // removed. + if (!frame_detached) + frame->document().removeEventListener("mousedown", this, false); +} + +void PageClickTracker::DidHandleMouseEvent(const WebMouseEvent& event) { + if (event.type != WebInputEvent::MouseDown || + last_node_clicked_.isNull()) { + return; + } + + // We are only interested in text field clicks. + if (!last_node_clicked_.isElementNode()) + return; + const WebElement& element = last_node_clicked_.toConst<WebElement>(); + if (!element.isFormControlElement()) + return; + const WebFormControlElement& control = + element.toConst<WebFormControlElement>(); + if (control.formControlType() != WebString::fromUTF8("text")) + return; + + const WebInputElement& input_element = element.toConst<WebInputElement>(); + + 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); +} + +void PageClickTracker::handleEvent(const WebDOMEvent& event) { + last_node_clicked_.reset(); + + DCHECK(event.isMouseEvent()); + 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. + last_node_clicked_ = mouse_event.target(); + 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(); +} |