Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement user interaction task source #10714

Merged
merged 4 commits into from May 12, 2016
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -173,15 +173,6 @@ impl<'a> GlobalRef<'a> {
}
}

/// `ScriptChan` used to send messages to the event loop of this global's
/// thread.
pub fn user_interaction_task_source(&self) -> Box<ScriptChan + Send> {
match *self {
GlobalRef::Window(ref window) => window.user_interaction_task_source(),
GlobalRef::Worker(ref worker) => worker.script_chan(),
}
}

/// `ScriptChan` used to send messages to the event loop of this global's
/// thread.
pub fn networking_task_source(&self) -> Box<ScriptChan + Send> {
@@ -74,7 +74,7 @@ impl VirtualMethods for HTMLDetailsElement {
let window = window.r();
let task_source = window.dom_manipulation_task_source();
let details = Trusted::new(self);
let runnable = box ToggleEventRunnable {
let runnable = box DetailsNotificationRunnable {
element: details,
toggle_number: counter
};
@@ -83,13 +83,13 @@ impl VirtualMethods for HTMLDetailsElement {
}
}

pub struct ToggleEventRunnable {
pub struct DetailsNotificationRunnable {
element: Trusted<HTMLDetailsElement>,
toggle_number: u32
}

impl Runnable for ToggleEventRunnable {
fn handler(self: Box<ToggleEventRunnable>) {
impl Runnable for DetailsNotificationRunnable {
fn handler(self: Box<DetailsNotificationRunnable>) {
let target = self.element.root();
if target.check_toggle_count(self.toggle_number) {
target.upcast::<EventTarget>().fire_simple_event("toggle");
@@ -12,10 +12,8 @@ use dom::bindings::codegen::Bindings::HTMLInputElementBinding;
use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
use dom::bindings::codegen::Bindings::KeyboardEventBinding::KeyboardEventMethods;
use dom::bindings::error::{Error, ErrorResult};
use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, LayoutJS, Root, RootedReference};
use dom::bindings::refcounted::Trusted;
use dom::document::Document;
use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers, LayoutElementHelpers};
use dom::event::{Event, EventBubbles, EventCancelable};
@@ -31,9 +29,7 @@ use dom::nodelist::NodeList;
use dom::validation::Validatable;
use dom::virtualmethods::VirtualMethods;
use msg::constellation_msg::ConstellationChan;
use script_runtime::CommonScriptMsg;
use script_runtime::ScriptThreadEventCategory::InputEvent;
use script_thread::Runnable;
use script_runtime::ScriptChan;
use script_traits::ScriptMsg as ConstellationMsg;
use std::borrow::ToOwned;
use std::cell::Cell;
@@ -549,6 +545,12 @@ impl HTMLInputElementMethods for HTMLInputElement {
let direction = direction.map_or(SelectionDirection::None, |d| SelectionDirection::from(d));
self.textinput.borrow_mut().selection_direction = direction;
self.textinput.borrow_mut().set_selection_range(start, end);
let window = window_from_node(self);
let _ = window.user_interaction_task_source().queue_event(
&self.upcast(),
atom!("select"),
EventBubbles::Bubbles,
EventCancelable::NotCancelable);
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
}
}
@@ -919,7 +921,12 @@ impl VirtualMethods for HTMLInputElement {
self.value_changed.set(true);

if event.IsTrusted() {
ChangeEventRunnable::send(self.upcast::<Node>());
let window = window_from_node(self);
let _ = window.user_interaction_task_source().queue_event(
&self.upcast(),
atom!("input"),
EventBubbles::Bubbles,
EventCancelable::NotCancelable);
}

self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
@@ -1148,31 +1155,3 @@ impl Activatable for HTMLInputElement {
}
}
}

pub struct ChangeEventRunnable {
element: Trusted<Node>,
}

impl ChangeEventRunnable {
pub fn send(node: &Node) {
let handler = Trusted::new(node);
let dispatcher = ChangeEventRunnable {
element: handler,
};
let chan = window_from_node(node).user_interaction_task_source();
let _ = chan.send(CommonScriptMsg::RunnableMsg(InputEvent, box dispatcher));
}
}

impl Runnable for ChangeEventRunnable {
fn handler(self: Box<ChangeEventRunnable>) {
let target = self.element.root();
let window = window_from_node(target.r());
let window = window.r();
let event = Event::new(GlobalRef::Window(window),
atom!("input"),
EventBubbles::Bubbles,
EventCancelable::NotCancelable);
target.upcast::<EventTarget>().dispatch_event(&event);
}
}
@@ -14,18 +14,18 @@ use dom::bindings::reflector::{Reflectable};
use dom::document::Document;
use dom::element::RawLayoutElementHelpers;
use dom::element::{AttributeMutation, Element};
use dom::event::{Event};
use dom::event::{Event, EventBubbles, EventCancelable};
use dom::htmlelement::HTMLElement;
use dom::htmlfieldsetelement::HTMLFieldSetElement;
use dom::htmlformelement::{FormControl, HTMLFormElement};
use dom::htmlinputelement::ChangeEventRunnable;
use dom::keyboardevent::KeyboardEvent;
use dom::node::{ChildrenMutation, Node, NodeDamage, UnbindContext};
use dom::node::{document_from_node};
use dom::node::{document_from_node, window_from_node};
use dom::nodelist::NodeList;
use dom::validation::Validatable;
use dom::virtualmethods::VirtualMethods;
use msg::constellation_msg::ConstellationChan;
use script_runtime::ScriptChan;
use script_traits::ScriptMsg as ConstellationMsg;
use std::cell::Cell;
use std::ops::Range;
@@ -256,6 +256,12 @@ impl HTMLTextAreaElementMethods for HTMLTextAreaElement {
let direction = direction.map_or(SelectionDirection::None, |d| SelectionDirection::from(d));
self.textinput.borrow_mut().selection_direction = direction;
self.textinput.borrow_mut().set_selection_range(start, end);
let window = window_from_node(self);
let _ = window.user_interaction_task_source().queue_event(
&self.upcast(),
atom!("select"),
EventBubbles::Bubbles,
EventCancelable::NotCancelable);
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
}
}
@@ -373,7 +379,12 @@ impl VirtualMethods for HTMLTextAreaElement {
self.value_changed.set(true);

if event.IsTrusted() {
ChangeEventRunnable::send(self.upcast::<Node>());
let window = window_from_node(self);
let _ = window.user_interaction_task_source().queue_event(
&self.upcast(),
atom!("input"),
EventBubbles::Bubbles,
EventCancelable::NotCancelable);
}

self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
@@ -277,7 +277,7 @@ impl Window {
self.dom_manipulation_task_source.clone()
}

pub fn user_interaction_task_source(&self) -> Box<ScriptChan + Send> {
pub fn user_interaction_task_source(&self) -> UserInteractionTaskSource {
self.user_interaction_task_source.clone()
}

@@ -100,7 +100,7 @@ use task_source::dom_manipulation::{DOMManipulationTaskSource, DOMManipulationTa
use task_source::file_reading::FileReadingTaskSource;
use task_source::history_traversal::HistoryTraversalTaskSource;
use task_source::networking::NetworkingTaskSource;
use task_source::user_interaction::UserInteractionTaskSource;
use task_source::user_interaction::{UserInteractionTaskSource, UserInteractionTask};
use time::Tm;
use url::{Url, Position};
use util::opts;
@@ -222,6 +222,8 @@ pub enum MainThreadScriptMsg {
Navigate(PipelineId, LoadData),
/// Tasks that originate from the DOM manipulation task source
DOMManipulation(DOMManipulationTask),
/// Tasks that originate from the user interaction task source
UserInteraction(UserInteractionTask),
}

impl OpaqueSender<CommonScriptMsg> for Box<ScriptChan + Send> {
@@ -932,8 +934,10 @@ impl ScriptThread {
LiveDOMReferences::cleanup(addr),
MainThreadScriptMsg::Common(CommonScriptMsg::CollectReports(reports_chan)) =>
self.collect_reports(reports_chan),
MainThreadScriptMsg::DOMManipulation(msg) =>
msg.handle_msg(self),
MainThreadScriptMsg::DOMManipulation(task) =>
task.handle_task(self),
MainThreadScriptMsg::UserInteraction(task) =>
task.handle_task(),
}
}

@@ -18,8 +18,10 @@ impl TaskSource<DOMManipulationTask> for DOMManipulationTaskSource {
fn queue(&self, msg: DOMManipulationTask) -> Result<(), ()> {
self.0.send(MainThreadScriptMsg::DOMManipulation(msg)).map_err(|_| ())
}
}

fn clone(&self) -> Box<TaskSource<DOMManipulationTask> + Send> {
impl DOMManipulationTaskSource {
pub fn clone(&self) -> Box<TaskSource<DOMManipulationTask> + Send> {
box DOMManipulationTaskSource((&self.0).clone())
}
}
@@ -42,7 +44,7 @@ pub enum DOMManipulationTask {
}

impl DOMManipulationTask {
pub fn handle_msg(self, script_thread: &ScriptThread) {
pub fn handle_task(self, script_thread: &ScriptThread) {
use self::DOMManipulationTask::*;

match self {
@@ -12,5 +12,4 @@ use std::result::Result;

pub trait TaskSource<T> {
fn queue(&self, msg: T) -> Result<(), ()>;
fn clone(&self) -> Box<TaskSource<T> + Send>;
}
@@ -2,19 +2,55 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use script_runtime::{CommonScriptMsg, ScriptChan};
use dom::bindings::refcounted::Trusted;
use dom::event::{EventBubbles, EventCancelable};
use dom::eventtarget::EventTarget;
use script_runtime::ScriptChan;
use script_thread::MainThreadScriptMsg;
use std::result::Result;
use std::sync::mpsc::Sender;
use string_cache::Atom;
use task_source::TaskSource;

#[derive(JSTraceable)]
pub struct UserInteractionTaskSource(pub Sender<MainThreadScriptMsg>);

impl ScriptChan for UserInteractionTaskSource {
fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> {
self.0.send(MainThreadScriptMsg::Common(msg)).map_err(|_| ())
impl TaskSource<UserInteractionTask> for UserInteractionTaskSource {
fn queue(&self, msg: UserInteractionTask) -> Result<(), ()> {
self.0.send(MainThreadScriptMsg::UserInteraction(msg)).map_err(|_| ())
}
}

impl UserInteractionTaskSource {
pub fn queue_event(&self,
target: &EventTarget,
name: Atom,
bubbles: EventBubbles,
cancelable: EventCancelable) {
let target = Trusted::new(target);
let _ = self.0.send(MainThreadScriptMsg::UserInteraction(UserInteractionTask::FireEvent(
target, name, bubbles, cancelable)));
}

pub fn clone(&self) -> UserInteractionTaskSource {
UserInteractionTaskSource((&self.0).clone())
}
}

pub enum UserInteractionTask {
// https://dom.spec.whatwg.org/#concept-event-fire
FireEvent(Trusted<EventTarget>, Atom, EventBubbles, EventCancelable),
}

impl UserInteractionTask {
pub fn handle_task(self) {
use self::UserInteractionTask::*;

fn clone(&self) -> Box<ScriptChan + Send> {
box UserInteractionTaskSource((&self.0).clone())
match self {
FireEvent(element, name, bubbles, cancelable) => {
let target = element.root();
target.fire_event(&*name, bubbles, cancelable);
}
}
}
}
@@ -116,6 +116,19 @@
},'input setSelectionRange(undefined,1)');
},"test of input.setSelectionRange");

async_test(function() {
var q = false;
var input = document.getElementById("a");
input.addEventListener("select", this.step_func_done(function(e) {
assert_true(q, "event should be queued");
assert_true(e.isTrusted, "event is trusted");
assert_true(e.bubbles, "event bubbles");
assert_false(e.cancelable, "event is not cancelable");
}));
input.setSelectionRange(0, 1);
q = true;
}, "input setSelectionRange fires a select event");

test(function() {
var textarea = document.getElementById("b");
test(function() {
@@ -221,4 +234,17 @@
assert_equals(textarea.selectionEnd, 1, "element.selectionStart should be 1");
},'textarea setSelectionRange(undefined,1)');
},"test of textarea.setSelectionRange");

async_test(function() {
var q = false;
var textarea = document.getElementById("b");
textarea.addEventListener("select", this.step_func_done(function(e) {
assert_true(q, "event should be queued");
assert_true(e.isTrusted, "event is trusted");
assert_true(e.bubbles, "event bubbles");
assert_false(e.cancelable, "event is not cancelable");
}));
textarea.setSelectionRange(0, 1);
q = true;
}, "textarea setSelectionRange fires a select event");
</script>
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.