Skip to content

Commit

Permalink
auto merge of #4999 : KiChjang/servo/refactor-handle-click-event, r=jdm
Browse files Browse the repository at this point in the history
Fixes #4983
  • Loading branch information
bors-servo committed Feb 21, 2015
2 parents ea9b090 + b855bc4 commit aad6cc0
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 77 deletions.
82 changes: 80 additions & 2 deletions components/script/dom/document.rs
Expand Up @@ -9,6 +9,7 @@ use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, Documen
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter;
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::codegen::InheritTypes::{DocumentDerived, EventCast, HTMLElementCast};
use dom::bindings::codegen::InheritTypes::{HTMLHeadElementCast, TextCast, ElementCast};
use dom::bindings::codegen::InheritTypes::{DocumentTypeCast, HTMLHtmlElementCast, NodeCast};
Expand All @@ -32,7 +33,7 @@ use dom::documentfragment::DocumentFragment;
use dom::documenttype::DocumentType;
use dom::domimplementation::DOMImplementation;
use dom::element::{Element, ElementCreator, AttributeHandlers, get_attribute_parts};
use dom::element::ElementTypeId;
use dom::element::{ElementTypeId, ActivationElementHelpers};
use dom::event::{Event, EventBubbles, EventCancelable, EventHelpers};
use dom::eventtarget::{EventTarget, EventTargetTypeId, EventTargetHelpers};
use dom::htmlanchorelement::HTMLAnchorElement;
Expand All @@ -45,7 +46,7 @@ use dom::location::Location;
use dom::mouseevent::MouseEvent;
use dom::keyboardevent::KeyboardEvent;
use dom::messageevent::MessageEvent;
use dom::node::{Node, NodeHelpers, NodeTypeId, CloneChildrenFlag, NodeDamage};
use dom::node::{self, Node, NodeHelpers, NodeTypeId, CloneChildrenFlag, NodeDamage};
use dom::nodelist::NodeList;
use dom::text::Text;
use dom::processinginstruction::ProcessingInstruction;
Expand All @@ -57,11 +58,14 @@ use net::resource_task::ControlMsg::{SetCookiesForUrl, GetCookiesForUrl};
use net::cookie_storage::CookieSource::NonHTTP;
use util::namespace;
use util::str::{DOMString, split_html_space_chars};
use layout_interface::{ReflowGoal, ReflowQueryType};

use geom::point::Point2D;
use html5ever::tree_builder::{QuirksMode, NoQuirks, LimitedQuirks, Quirks};
use layout_interface::{LayoutChan, Msg};
use string_cache::{Atom, QualName};
use url::Url;
use js::jsapi::JSRuntime;

use std::borrow::ToOwned;
use std::collections::HashMap;
Expand Down Expand Up @@ -191,6 +195,7 @@ pub trait DocumentHelpers<'a> {
fn commit_focus_transaction(self);
fn send_title_to_compositor(self);
fn dirty_all_nodes(self);
fn handle_click_event(self, js_runtime: *mut JSRuntime, _button: uint, point: Point2D<f32>);
}

impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> {
Expand Down Expand Up @@ -386,6 +391,61 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> {
node.dirty(NodeDamage::OtherNodeDamage)
}
}

fn handle_click_event(self, js_runtime: *mut JSRuntime, _button: uint, point: Point2D<f32>) {
debug!("ClickEvent: clicked at {:?}", point);
let window = self.window.root();
let window = window.r();
let page = window.page();
match page.hit_test(&point) {
Some(node_address) => {
debug!("node address is {:?}", node_address.0);

let temp_node =
node::from_untrusted_node_address(
js_runtime, node_address).root();

let maybe_elem: Option<JSRef<Element>> = ElementCast::to_ref(temp_node.r());
let maybe_node = match maybe_elem {
Some(element) => Some(element),
None => temp_node.r().ancestors().filter_map(ElementCast::to_ref).next(),
};

match maybe_node {
Some(el) => {
let node: JSRef<Node> = NodeCast::from_ref(el);
debug!("clicked on {:?}", node.debug_str());
// Prevent click event if form control element is disabled.
if node.click_event_filter_by_disabled_state() { return; }
match *page.frame() {
Some(ref frame) => {
let window = frame.window.root();
let doc = window.r().Document().root();
doc.r().begin_focus_transaction();

let event =
Event::new(GlobalRef::Window(window.r()),
"click".to_owned(),
EventBubbles::Bubbles,
EventCancelable::Cancelable).root();
// https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#trusted-events
event.r().set_trusted(true);
// https://html.spec.whatwg.org/multipage/interaction.html#run-authentic-click-activation-steps
el.authentic_click_activation(event.r());

doc.r().commit_focus_transaction();
window.r().flush_layout(ReflowGoal::ForDisplay, ReflowQueryType::NoQuery);
}
None => {}
}
}
None => {}
}
}

None => {}
}
}
}

#[derive(PartialEq)]
Expand Down Expand Up @@ -506,6 +566,24 @@ impl<'a> PrivateDocumentHelpers for JSRef<'a, Document> {
}
}

trait PrivateClickEventHelpers {
fn click_event_filter_by_disabled_state(&self) -> bool;
}

impl<'a> PrivateClickEventHelpers for JSRef<'a, Node> {
fn click_event_filter_by_disabled_state(&self) -> bool {
match self.type_id() {
NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLButtonElement)) |
NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLInputElement)) |
// NodeTypeId::Element(ElementTypeId::HTMLKeygenElement) |
NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptionElement)) |
NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSelectElement)) |
NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement)) if self.get_disabled_state() => true,
_ => false
}
}
}

impl<'a> DocumentMethods for JSRef<'a, Document> {
// http://dom.spec.whatwg.org/#dom-document-implementation
fn Implementation(self) -> Temporary<DOMImplementation> {
Expand Down
81 changes: 6 additions & 75 deletions components/script/script_task.rs
Expand Up @@ -23,15 +23,14 @@ use dom::bindings::structuredclone::StructuredCloneData;
use dom::bindings::trace::JSTraceable;
use dom::bindings::utils::{wrap_for_same_compartment, pre_wrap};
use dom::document::{Document, IsHTMLDocument, DocumentHelpers, DocumentSource};
use dom::element::{Element, ElementTypeId, ActivationElementHelpers};
use dom::element::{Element, ActivationElementHelpers};
use dom::event::{Event, EventHelpers, EventBubbles, EventCancelable};
use dom::uievent::UIEvent;
use dom::eventtarget::{EventTarget, EventTargetHelpers};
use dom::htmlelement::HTMLElementTypeId;
use dom::htmliframeelement::HTMLIFrameElement;
use dom::keyboardevent::KeyboardEvent;
use dom::mouseevent::MouseEvent;
use dom::node::{self, Node, NodeHelpers, NodeDamage, NodeTypeId, window_from_node};
use dom::node::{self, Node, NodeHelpers, NodeDamage, window_from_node};
use dom::window::{Window, WindowHelpers, ScriptHelpers};
use dom::worker::{Worker, TrustedWorkerAddress};
use parse::html::{HTMLInput, parse_html};
Expand Down Expand Up @@ -265,24 +264,6 @@ impl<'a> Drop for ScriptMemoryFailsafe<'a> {
}
}

trait PrivateScriptTaskHelpers {
fn click_event_filter_by_disabled_state(&self) -> bool;
}

impl<'a> PrivateScriptTaskHelpers for JSRef<'a, Node> {
fn click_event_filter_by_disabled_state(&self) -> bool {
match self.type_id() {
NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLButtonElement)) |
NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLInputElement)) |
// NodeTypeId::Element(ElementTypeId::HTMLKeygenElement) |
NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptionElement)) |
NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSelectElement)) |
NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement)) if self.get_disabled_state() => true,
_ => false
}
}
}

impl ScriptTaskFactory for ScriptTask {
fn create_layout_channel(_phantom: Option<&mut ScriptTask>) -> OpaqueScriptLayoutChannel {
let (chan, port) = channel();
Expand Down Expand Up @@ -1008,7 +989,10 @@ impl ScriptTask {
}

ClickEvent(_button, point) => {
self.handle_click_event(pipeline_id, _button, point);
let page = get_page(&*self.page.borrow(), pipeline_id);
let frame = page.frame();
let document = frame.as_ref().unwrap().document.root();
document.r().handle_click_event(self.js_runtime.ptr, _button, point);
}

MouseDownEvent(..) => {}
Expand Down Expand Up @@ -1174,59 +1158,6 @@ impl ScriptTask {
}
}

fn handle_click_event(&self, pipeline_id: PipelineId, _button: uint, point: Point2D<f32>) {
debug!("ClickEvent: clicked at {:?}", point);
let page = get_page(&*self.page.borrow(), pipeline_id);
match page.hit_test(&point) {
Some(node_address) => {
debug!("node address is {:?}", node_address.0);

let temp_node =
node::from_untrusted_node_address(
self.js_runtime.ptr, node_address).root();

let maybe_elem: Option<JSRef<Element>> = ElementCast::to_ref(temp_node.r());
let maybe_node = match maybe_elem {
Some(element) => Some(element),
None => temp_node.r().ancestors().filter_map(ElementCast::to_ref).next(),
};

match maybe_node {
Some(el) => {
let node: JSRef<Node> = NodeCast::from_ref(el);
debug!("clicked on {:?}", node.debug_str());
// Prevent click event if form control element is disabled.
if node.click_event_filter_by_disabled_state() { return; }
match *page.frame() {
Some(ref frame) => {
let window = frame.window.root();
let doc = window.r().Document().root();
doc.r().begin_focus_transaction();

let event =
Event::new(GlobalRef::Window(window.r()),
"click".to_owned(),
EventBubbles::Bubbles,
EventCancelable::Cancelable).root();
// https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#trusted-events
event.r().set_trusted(true);
// https://html.spec.whatwg.org/multipage/interaction.html#run-authentic-click-activation-steps
el.authentic_click_activation(event.r());

doc.r().commit_focus_transaction();
window.r().flush_layout(ReflowGoal::ForDisplay, ReflowQueryType::NoQuery);
}
None => {}
}
}
None => {}
}
}

None => {}
}
}


fn handle_mouse_move_event(&self, pipeline_id: PipelineId, point: Point2D<f32>) {
let page = get_page(&*self.page.borrow(), pipeline_id);
Expand Down

0 comments on commit aad6cc0

Please sign in to comment.