1// Copyright 2013 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 "components/autofill/content/renderer/page_click_tracker.h" 6 7#include "base/bind.h" 8#include "base/message_loop/message_loop.h" 9#include "components/autofill/content/renderer/form_autofill_util.h" 10#include "components/autofill/content/renderer/page_click_listener.h" 11#include "content/public/renderer/render_view.h" 12#include "third_party/WebKit/public/platform/WebString.h" 13#include "third_party/WebKit/public/web/WebDOMMouseEvent.h" 14#include "third_party/WebKit/public/web/WebDocument.h" 15#include "third_party/WebKit/public/web/WebInputElement.h" 16#include "third_party/WebKit/public/web/WebInputEvent.h" 17#include "third_party/WebKit/public/web/WebLocalFrame.h" 18#include "third_party/WebKit/public/web/WebTextAreaElement.h" 19#include "third_party/WebKit/public/web/WebView.h" 20 21using blink::WebDOMEvent; 22using blink::WebDOMMouseEvent; 23using blink::WebElement; 24using blink::WebFormControlElement; 25using blink::WebFrame; 26using blink::WebGestureEvent; 27using blink::WebInputElement; 28using blink::WebInputEvent; 29using blink::WebMouseEvent; 30using blink::WebNode; 31using blink::WebString; 32using blink::WebTextAreaElement; 33using blink::WebView; 34 35namespace { 36 37// Casts |node| to a WebInputElement. 38// Returns an empty (isNull()) WebInputElement if |node| is not a text field. 39const WebInputElement GetTextWebInputElement(const WebNode& node) { 40 if (!node.isElementNode()) 41 return WebInputElement(); 42 const WebElement element = node.toConst<WebElement>(); 43 if (!element.hasHTMLTagName("input")) 44 return WebInputElement(); 45 const WebInputElement* input = blink::toWebInputElement(&element); 46 if (!autofill::IsTextInput(input)) 47 return WebInputElement(); 48 return *input; 49} 50 51// Casts |node| to a WebTextAreaElement. 52// Returns an empty (isNull()) WebTextAreaElement if |node| is not a 53// textarea field. 54const WebTextAreaElement GetWebTextAreaElement(const WebNode& node) { 55 if (!node.isElementNode()) 56 return WebTextAreaElement(); 57 const WebElement element = node.toConst<WebElement>(); 58 if (!element.hasHTMLTagName("textarea")) 59 return WebTextAreaElement(); 60 return element.toConst<WebTextAreaElement>(); 61} 62 63} // namespace 64 65namespace autofill { 66 67PageClickTracker::PageClickTracker(content::RenderView* render_view, 68 PageClickListener* listener) 69 : content::RenderViewObserver(render_view), 70 was_focused_before_now_(false), 71 listener_(listener), 72 weak_ptr_factory_(this) { 73} 74 75PageClickTracker::~PageClickTracker() { 76} 77 78void PageClickTracker::DidHandleMouseEvent(const WebMouseEvent& event) { 79 if (event.type != WebInputEvent::MouseDown || 80 event.button != WebMouseEvent::ButtonLeft) { 81 return; 82 } 83 84 PotentialActivationAt(event.x, event.y); 85} 86 87void PageClickTracker::DidHandleGestureEvent( 88 const blink::WebGestureEvent& event) { 89 if (event.type != blink::WebGestureEvent::GestureTap) 90 return; 91 92 PotentialActivationAt(event.x, event.y); 93} 94 95void PageClickTracker::FocusedNodeChanged(const blink::WebNode& node) { 96 was_focused_before_now_ = false; 97 // If the focus change was a result of handling a click or tap, we'll soon get 98 // an associated event. Reset |was_focused_before_now_| to true only after the 99 // message loop unwinds. 100 base::MessageLoop::current()->PostTask( 101 FROM_HERE, 102 base::Bind(&PageClickTracker::SetWasFocused, 103 weak_ptr_factory_.GetWeakPtr())); 104} 105 106void PageClickTracker::PotentialActivationAt(int x, int y) { 107 blink::WebNode focused_node = render_view()->GetFocusedElement(); 108 if (focused_node.isNull()) 109 return; 110 111 if (!render_view()->NodeContainsPoint(focused_node, gfx::Point(x, y))) 112 return; 113 114 const WebInputElement input_element = GetTextWebInputElement(focused_node); 115 if (!input_element.isNull()) { 116 listener_->FormControlElementClicked(input_element, 117 was_focused_before_now_); 118 return; 119 } 120 121 const WebTextAreaElement textarea_element = 122 GetWebTextAreaElement(focused_node); 123 if (!textarea_element.isNull()) { 124 listener_->FormControlElementClicked(textarea_element, 125 was_focused_before_now_); 126 } 127} 128 129void PageClickTracker::SetWasFocused() { 130 was_focused_before_now_ = true; 131} 132 133} // namespace autofill 134