aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
Diffstat (limited to 'components/script')
-rw-r--r--components/script/dom/bindings/callback.rs34
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py44
-rw-r--r--components/script/dom/browsercontext.rs125
-rw-r--r--components/script/dom/element.rs17
-rw-r--r--components/script/dom/eventdispatcher.rs8
-rw-r--r--components/script/dom/treewalker.rs4
-rw-r--r--components/script/dom/window.rs7
-rw-r--r--components/script/lib.rs2
-rw-r--r--components/script/textinput.rs168
-rw-r--r--components/script/timers.rs4
10 files changed, 346 insertions, 67 deletions
diff --git a/components/script/dom/bindings/callback.rs b/components/script/dom/bindings/callback.rs
index 29741117383..6b8fcc09e34 100644
--- a/components/script/dom/bindings/callback.rs
+++ b/components/script/dom/bindings/callback.rs
@@ -9,23 +9,20 @@
use dom::bindings::global::global_object_for_js_object;
use dom::bindings::js::JSRef;
use dom::bindings::utils::Reflectable;
-use js::jsapi::{JSContext, JSObject, JS_WrapObject, JS_ObjectIsCallable};
-use js::jsapi::JS_GetProperty;
+use js::jsapi::{JSContext, JSObject, JS_WrapObject, JS_ObjectIsCallable, JS_GetGlobalObject};
+use js::jsapi::{JS_GetProperty, JS_IsExceptionPending, JS_ReportPendingException};
use js::jsval::{JSVal, UndefinedValue};
+use js::rust::with_compartment;
use std::ptr;
/// The exception handling used for a call.
-#[deriving(Copy)]
+#[deriving(Copy, PartialEq)]
pub enum ExceptionHandling {
/// Report any exception and don't throw it to the caller code.
- ReportExceptions,
- /// Throw an exception to the caller code if the thrown exception is a
- /// binding object for a DOMError from the caller's scope, otherwise report
- /// it.
- RethrowContentExceptions,
+ Report,
/// Throw any exception to the caller code.
- RethrowExceptions
+ Rethrow
}
/// A common base class for representing IDL callback function types.
@@ -139,7 +136,7 @@ pub struct CallSetup {
/// The `JSContext` used for the call.
cx: *mut JSContext,
/// The exception handling used for the call.
- _handling: ExceptionHandling
+ _handling: ExceptionHandling,
}
impl CallSetup {
@@ -149,9 +146,10 @@ impl CallSetup {
let global = global_object_for_js_object(callback.callback());
let global = global.root();
let cx = global.r().get_cx();
+
CallSetup {
cx: cx,
- _handling: handling
+ _handling: handling,
}
}
@@ -160,3 +158,17 @@ impl CallSetup {
self.cx
}
}
+
+impl Drop for CallSetup {
+ fn drop(&mut self) {
+ let need_to_deal_with_exception = unsafe { JS_IsExceptionPending(self.cx) } != 0;
+ if need_to_deal_with_exception {
+ unsafe {
+ let old_global = JS_GetGlobalObject(self.cx);
+ with_compartment(self.cx, old_global, || {
+ JS_ReportPendingException(self.cx)
+ });
+ }
+ }
+ }
+}
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py
index c1c4aca60ca..1cc9c2dc9e8 100644
--- a/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/components/script/dom/bindings/codegen/CodegenRust.py
@@ -4837,12 +4837,11 @@ class FakeMember():
return None
class CallbackMember(CGNativeMember):
- def __init__(self, sig, name, descriptorProvider, needThisHandling, rethrowContentException=False):
+ def __init__(self, sig, name, descriptorProvider, needThisHandling):
"""
needThisHandling is True if we need to be able to accept a specified
thisObj, False otherwise.
"""
- assert not rethrowContentException or not needThisHandling
self.retvalType = sig[0]
self.originalSig = sig
@@ -4861,7 +4860,6 @@ class CallbackMember(CGNativeMember):
# If needThisHandling, we generate ourselves as private and the caller
# will handle generating public versions that handle the "this" stuff.
visibility = "priv" if needThisHandling else "pub"
- self.rethrowContentException = rethrowContentException
# We don't care, for callback codegen, whether our original member was
# a method or attribute or whatnot. Just always pass FakeMember()
# here.
@@ -4984,11 +4982,8 @@ class CallbackMember(CGNativeMember):
if not self.needThisHandling:
# Since we don't need this handling, we're the actual method that
# will be called, so we need an aRethrowExceptions argument.
- if self.rethrowContentException:
- args.append(Argument("JSCompartment*", "aCompartment", "nullptr"))
- else:
- args.append(Argument("ExceptionHandling", "aExceptionHandling",
- "ReportExceptions"))
+ args.append(Argument("ExceptionHandling", "aExceptionHandling",
+ "ReportExceptions"))
return args
# We want to allow the caller to pass in a "this" object, as
# well as a JSContext.
@@ -4999,22 +4994,12 @@ class CallbackMember(CGNativeMember):
if self.needThisHandling:
# It's been done for us already
return ""
- callSetup = "CallSetup s(CallbackPreserveColor(), aRv"
- if self.rethrowContentException:
- # getArgs doesn't add the aExceptionHandling argument but does add
- # aCompartment for us.
- callSetup += ", RethrowContentExceptions, aCompartment"
- else:
- callSetup += ", aExceptionHandling"
- callSetup += ");"
- return string.Template(
- "${callSetup}\n"
+ return (
+ "CallSetup s(CallbackPreserveColor(), aRv, aExceptionHandling);\n"
"JSContext* cx = s.GetContext();\n"
"if (!cx) {\n"
" return Err(FailureUnknown);\n"
- "}\n").substitute({
- "callSetup": callSetup,
- })
+ "}\n")
def getArgcDecl(self):
return CGGeneric("let mut argc = %s as u32;" % self.argCountStr);
@@ -5035,9 +5020,9 @@ class CallbackMember(CGNativeMember):
idlObject.location))
class CallbackMethod(CallbackMember):
- def __init__(self, sig, name, descriptorProvider, needThisHandling, rethrowContentException=False):
+ def __init__(self, sig, name, descriptorProvider, needThisHandling):
CallbackMember.__init__(self, sig, name, descriptorProvider,
- needThisHandling, rethrowContentException)
+ needThisHandling)
def getRvalDecl(self):
return "let mut rval = UndefinedValue();\n"
@@ -5076,10 +5061,10 @@ class CallbackOperationBase(CallbackMethod):
"""
Common class for implementing various callback operations.
"""
- def __init__(self, signature, jsName, nativeName, descriptor, singleOperation, rethrowContentException=False):
+ def __init__(self, signature, jsName, nativeName, descriptor, singleOperation):
self.singleOperation = singleOperation
self.methodName = jsName
- CallbackMethod.__init__(self, signature, nativeName, descriptor, singleOperation, rethrowContentException)
+ CallbackMethod.__init__(self, signature, nativeName, descriptor, singleOperation)
def getThisObj(self):
if not self.singleOperation:
@@ -5117,8 +5102,7 @@ class CallbackOperation(CallbackOperationBase):
jsName = method.identifier.name
CallbackOperationBase.__init__(self, signature,
jsName, MakeNativeName(jsName),
- descriptor, descriptor.interface.isSingleOperationInterface(),
- rethrowContentException=descriptor.interface.isJSImplemented())
+ descriptor, descriptor.interface.isSingleOperationInterface())
class CallbackGetter(CallbackMember):
def __init__(self, attr, descriptor):
@@ -5128,8 +5112,7 @@ class CallbackGetter(CallbackMember):
(attr.type, []),
callbackGetterName(attr),
descriptor,
- needThisHandling=False,
- rethrowContentException=descriptor.interface.isJSImplemented())
+ needThisHandling=False)
def getRvalDecl(self):
return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
@@ -5152,8 +5135,7 @@ class CallbackSetter(CallbackMember):
[FakeArgument(attr.type, attr)]),
callbackSetterName(attr),
descriptor,
- needThisHandling=False,
- rethrowContentException=descriptor.interface.isJSImplemented())
+ needThisHandling=False)
def getRvalDecl(self):
# We don't need an rval
diff --git a/components/script/dom/browsercontext.rs b/components/script/dom/browsercontext.rs
index 9cc2a94fdb9..959c021b4bc 100644
--- a/components/script/dom/browsercontext.rs
+++ b/components/script/dom/browsercontext.rs
@@ -2,14 +2,27 @@
* 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 dom::bindings::js::{JS, JSRef, Temporary};
+use dom::bindings::conversions::unwrap_jsmanaged;
+use dom::bindings::conversions::{ToJSValConvertible};
+use dom::bindings::js::{JS, JSRef, Temporary, Root};
+use dom::bindings::js::{OptionalRootable, OptionalRootedRootable, ResultRootable};
+use dom::bindings::js::{OptionalRootedReference, OptionalOptionalRootedRootable};
+use dom::bindings::proxyhandler::{getPropertyDescriptor, FillPropertyDescriptor};
use dom::bindings::utils::{Reflectable, WindowProxyHandler};
+use dom::bindings::utils::{GetArrayIndexFromId};
use dom::document::{Document, DocumentHelpers};
use dom::window::Window;
-
-use js::jsapi::JSObject;
+use dom::window::WindowHelpers;
+
+use js::jsapi::{JSContext, JSObject, jsid, JSPropertyDescriptor};
+use js::jsapi::{JS_AlreadyHasOwnPropertyById, JS_ForwardGetPropertyTo};
+use js::jsapi::{JS_GetPropertyDescriptorById, JS_DefinePropertyById};
+use js::jsapi::{JS_SetPropertyById};
+use js::jsval::JSVal;
+use js::glue::{GetProxyPrivate};
use js::glue::{WrapperNew, CreateWrapperProxyHandler, ProxyTraps};
use js::rust::with_compartment;
+use js::{JSRESOLVE_QUALIFIED, JSRESOLVE_ASSIGNING};
use std::ptr;
@@ -86,18 +99,112 @@ impl SessionHistoryEntry {
}
}
+unsafe fn GetSubframeWindow(cx: *mut JSContext, proxy: *mut JSObject, id: jsid) -> Option<Temporary<Window>> {
+ let index = GetArrayIndexFromId(cx, id);
+ if let Some(index) = index {
+ let target = GetProxyPrivate(proxy).to_object();
+ let win: Root<Window> = unwrap_jsmanaged(target).unwrap().root();
+ let mut found = false;
+ return win.r().IndexedGetter(index, &mut found);
+ }
+
+ None
+}
+
+unsafe extern fn getOwnPropertyDescriptor(cx: *mut JSContext, proxy: *mut JSObject, id: jsid, set: bool, desc: *mut JSPropertyDescriptor) -> bool {
+ let window = GetSubframeWindow(cx, proxy, id);
+ if let Some(window) = window {
+ let window = window.root();
+ (*desc).value = window.to_jsval(cx);
+ FillPropertyDescriptor(&mut *desc, proxy, true);
+ return true;
+ }
+
+ let target = GetProxyPrivate(proxy).to_object();
+ let flags = if set { JSRESOLVE_ASSIGNING } else { 0 } | JSRESOLVE_QUALIFIED;
+ // XXX This should be JS_GetOwnPropertyDescriptorById
+ if JS_GetPropertyDescriptorById(cx, target, id, flags, desc) == 0 {
+ return false;
+ }
+
+ if (*desc).obj != target {
+ // Not an own property
+ (*desc).obj = ptr::null_mut();
+ } else {
+ (*desc).obj = proxy;
+ }
+
+ true
+}
+
+
+unsafe extern fn defineProperty(cx: *mut JSContext, proxy: *mut JSObject, id: jsid, desc: *mut JSPropertyDescriptor) -> bool {
+ if GetArrayIndexFromId(cx, id).is_some() {
+ // Spec says to Reject whether this is a supported index or not,
+ // since we have no indexed setter or indexed creator. That means
+ // throwing in strict mode (FIXME: Bug 828137), doing nothing in
+ // non-strict mode.
+ return true;
+ }
+
+ let target = GetProxyPrivate(proxy).to_object();
+ JS_DefinePropertyById(cx, target, id, (*desc).value, (*desc).getter,
+ (*desc).setter, (*desc).attrs) != 0
+}
+
+unsafe extern fn hasOwn(cx: *mut JSContext, proxy: *mut JSObject, id: jsid, bp: *mut bool) -> bool {
+ let window = GetSubframeWindow(cx, proxy, id);
+ if window.is_some() {
+ *bp = true;
+ return true;
+ }
+
+ let target = GetProxyPrivate(proxy).to_object();
+ let mut found = 0;
+ if JS_AlreadyHasOwnPropertyById(cx, target, id, &mut found) == 0 {
+ return false;
+ }
+
+ *bp = found != 0;
+ return true;
+}
+
+unsafe extern fn get(cx: *mut JSContext, proxy: *mut JSObject, receiver: *mut JSObject, id: jsid, vp: *mut JSVal) -> bool {
+ let window = GetSubframeWindow(cx, proxy, id);
+ if let Some(window) = window {
+ let window = window.root();
+ *vp = window.to_jsval(cx);
+ return true;
+ }
+
+ let target = GetProxyPrivate(proxy).to_object();
+ JS_ForwardGetPropertyTo(cx, target, id, receiver, vp) != 0
+}
+
+unsafe extern fn set(cx: *mut JSContext, proxy: *mut JSObject, _receiver: *mut JSObject, id: jsid, _strict: bool, vp: *mut JSVal) -> bool {
+ if GetArrayIndexFromId(cx, id).is_some() {
+ // Reject (which means throw if and only if strict) the set.
+ // FIXME: Throw
+ return true;
+ }
+
+ // FIXME: The receiver should be used, we need something like JS_ForwardSetPropertyTo.
+ let target = GetProxyPrivate(proxy).to_object();
+ JS_SetPropertyById(cx, target, id, vp) != 0
+}
+
static PROXY_HANDLER: ProxyTraps = ProxyTraps {
- getPropertyDescriptor: None,
- getOwnPropertyDescriptor: None,
- defineProperty: None,
+ getPropertyDescriptor: Some(getPropertyDescriptor),
+ getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor),
+ defineProperty: Some(defineProperty),
getOwnPropertyNames: None,
delete_: None,
enumerate: None,
has: None,
- hasOwn: None,
- get: None,
- set: None,
+ hasOwn: Some(hasOwn),
+ get: Some(get),
+ set: Some(set),
keys: None,
iterate: None,
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index df99f4dc91d..129756c1575 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -55,6 +55,8 @@ use style::{IntegerAttribute, LengthAttribute, ParserContext, matches};
use servo_util::namespace;
use servo_util::str::{DOMString, LengthOrPercentageOrAuto};
+use html5ever::tree_builder::{NoQuirks, LimitedQuirks, Quirks};
+
use cssparser::RGBA;
use std::ascii::AsciiExt;
use std::cell::{Ref, RefMut};
@@ -571,7 +573,7 @@ pub trait AttributeHandlers {
value: DOMString) -> AttrValue;
fn remove_attribute(self, namespace: Namespace, name: &str);
- fn has_class(&self, name: &Atom) -> bool;
+ fn has_class(self, name: &Atom) -> bool;
fn set_atomic_attribute(self, name: &Atom, value: DOMString);
@@ -713,10 +715,19 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> {
};
}
- fn has_class(&self, name: &Atom) -> bool {
+ fn has_class(self, name: &Atom) -> bool {
+ let quirks_mode = {
+ let node: JSRef<Node> = NodeCast::from_ref(self);
+ let owner_doc = node.owner_doc().root();
+ owner_doc.r().quirks_mode()
+ };
+ let is_equal = |lhs: &Atom, rhs: &Atom| match quirks_mode {
+ NoQuirks | LimitedQuirks => lhs == rhs,
+ Quirks => lhs.as_slice().eq_ignore_ascii_case(rhs.as_slice())
+ };
self.get_attribute(ns!(""), &atom!("class")).root().map(|attr| {
attr.r().value().tokens().map(|tokens| {
- tokens.iter().any(|atom| atom == name)
+ tokens.iter().any(|atom| is_equal(name, atom))
}).unwrap_or(false)
}).unwrap_or(false)
}
diff --git a/components/script/dom/eventdispatcher.rs b/components/script/dom/eventdispatcher.rs
index d76c3002d8f..3518ff20eb6 100644
--- a/components/script/dom/eventdispatcher.rs
+++ b/components/script/dom/eventdispatcher.rs
@@ -2,7 +2,7 @@
* 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 dom::bindings::callback::ExceptionHandling::ReportExceptions;
+use dom::bindings::callback::ExceptionHandling::Report;
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::InheritTypes::{EventTargetCast, NodeCast, NodeDerived};
use dom::bindings::js::{JS, JSRef, OptionalRootable, Root};
@@ -48,7 +48,7 @@ pub fn dispatch_event<'a, 'b>(target: JSRef<'a, EventTarget>,
event.set_current_target(cur_target.r());
for listener in listeners.iter() {
// Explicitly drop any exception on the floor.
- let _ = listener.HandleEvent_(cur_target.r(), event, ReportExceptions);
+ let _ = listener.HandleEvent_(cur_target.r(), event, Report);
if event.stop_immediate() {
break;
@@ -74,7 +74,7 @@ pub fn dispatch_event<'a, 'b>(target: JSRef<'a, EventTarget>,
for listeners in opt_listeners.iter() {
for listener in listeners.iter() {
// Explicitly drop any exception on the floor.
- let _ = listener.HandleEvent_(target, event, ReportExceptions);
+ let _ = listener.HandleEvent_(target, event, Report);
if event.stop_immediate() {
break;
@@ -93,7 +93,7 @@ pub fn dispatch_event<'a, 'b>(target: JSRef<'a, EventTarget>,
event.set_current_target(cur_target.r());
for listener in listeners.iter() {
// Explicitly drop any exception on the floor.
- let _ = listener.HandleEvent_(cur_target.r(), event, ReportExceptions);
+ let _ = listener.HandleEvent_(cur_target.r(), event, Report);
if event.stop_immediate() {
break;
diff --git a/components/script/dom/treewalker.rs b/components/script/dom/treewalker.rs
index 8cae9d08269..b578823acd6 100644
--- a/components/script/dom/treewalker.rs
+++ b/components/script/dom/treewalker.rs
@@ -2,7 +2,7 @@
* 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 dom::bindings::callback::ExceptionHandling::RethrowExceptions;
+use dom::bindings::callback::ExceptionHandling::Rethrow;
use dom::bindings::codegen::Bindings::TreeWalkerBinding;
use dom::bindings::codegen::Bindings::TreeWalkerBinding::TreeWalkerMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
@@ -325,7 +325,7 @@ impl<'a> PrivateTreeWalkerHelpers<'a> for JSRef<'a, TreeWalker> {
match self.filter {
Filter::None => Ok(NodeFilterConstants::FILTER_ACCEPT),
Filter::Native(f) => Ok((f)(node)),
- Filter::JS(callback) => callback.AcceptNode_(self, node, RethrowExceptions)
+ Filter::JS(callback) => callback.AcceptNode_(self, node, Rethrow)
}
}
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 91d023eec18..91402fe6c1f 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -311,12 +311,12 @@ impl<'a> WindowMethods for JSRef<'a, Window> {
}
}
-
pub trait WindowHelpers {
fn flush_layout(self, goal: ReflowGoal, query: ReflowQueryType);
fn init_browser_context(self, doc: JSRef<Document>);
fn load_url(self, href: DOMString);
fn handle_fire_timer(self, timer_id: TimerId);
+ fn IndexedGetter(self, _index: u32, _found: &mut bool) -> Option<Temporary<Window>>;
}
pub trait ScriptHelpers {
@@ -378,6 +378,11 @@ impl<'a> WindowHelpers for JSRef<'a, Window> {
self.timers.fire_timer(timer_id, self);
self.flush_layout(ReflowGoal::ForDisplay, ReflowQueryType::NoQuery);
}
+
+ // https://html.spec.whatwg.org/multipage/browsers.html#accessing-other-browsing-contexts
+ fn IndexedGetter(self, _index: u32, _found: &mut bool) -> Option<Temporary<Window>> {
+ None
+ }
}
impl Window {
diff --git a/components/script/lib.rs b/components/script/lib.rs
index 50661a60ca1..7593a3b68a3 100644
--- a/components/script/lib.rs
+++ b/components/script/lib.rs
@@ -62,7 +62,7 @@ pub mod dom {
pub mod callback;
pub mod error;
pub mod conversions;
- mod proxyhandler;
+ pub mod proxyhandler;
pub mod str;
pub mod structuredclone;
pub mod trace;
diff --git a/components/script/textinput.rs b/components/script/textinput.rs
index 03f8f95b435..809fc56de2d 100644
--- a/components/script/textinput.rs
+++ b/components/script/textinput.rs
@@ -130,7 +130,7 @@ impl TextInput {
fn replace_selection(&mut self, insert: String) {
let (begin, end) = self.get_sorted_selection();
- self.selection_begin = None;
+ self.clear_selection();
let new_lines = {
let prefix = self.lines[begin.line].slice_chars(0, begin.index);
@@ -181,7 +181,7 @@ impl TextInput {
self.selection_begin = Some(self.edit_point);
}
} else {
- self.selection_begin = None;
+ self.clear_selection();
}
assert!(self.edit_point.line < self.lines.len());
@@ -214,7 +214,7 @@ impl TextInput {
if self.selection_begin.is_some() {
let (begin, end) = self.get_sorted_selection();
self.edit_point = if adjust < 0 {begin} else {end};
- self.selection_begin = None;
+ self.clear_selection();
return
}
}
@@ -262,6 +262,11 @@ impl TextInput {
self.edit_point.index = self.lines[last_line].char_len();
}
+ /// Remove the current selection.
+ fn clear_selection(&mut self) {
+ self.selection_begin = None;
+ }
+
/// Process a given `KeyboardEvent` and return an action for the caller to execute.
pub fn handle_keydown(&mut self, event: JSRef<KeyboardEvent>) -> KeyReaction {
//A simple way to convert an event to a selection
@@ -361,3 +366,160 @@ impl TextInput {
}
}
}
+
+#[test]
+fn test_textinput_delete_char() {
+ let mut textinput = TextInput::new(Lines::Single, "abcdefg".into_string());
+ textinput.adjust_horizontal(2, Selection::NotSelected);
+ textinput.delete_char(DeleteDir::Backward);
+ assert_eq!(textinput.get_content().as_slice(), "acdefg");
+
+ textinput.delete_char(DeleteDir::Forward);
+ assert_eq!(textinput.get_content().as_slice(), "adefg");
+
+ textinput.adjust_horizontal(2, Selection::Selected);
+ textinput.delete_char(DeleteDir::Forward);
+ assert_eq!(textinput.get_content().as_slice(), "afg");
+}
+
+#[test]
+fn test_textinput_insert_char() {
+ let mut textinput = TextInput::new(Lines::Single, "abcdefg".into_string());
+ textinput.adjust_horizontal(2, Selection::NotSelected);
+ textinput.insert_char('a');
+ assert_eq!(textinput.get_content().as_slice(), "abacdefg");
+
+ textinput.adjust_horizontal(2, Selection::Selected);
+ textinput.insert_char('b');
+ assert_eq!(textinput.get_content().as_slice(), "ababefg");
+}
+
+#[test]
+fn test_textinput_get_sorted_selection() {
+ let mut textinput = TextInput::new(Lines::Single, "abcdefg".into_string());
+ textinput.adjust_horizontal(2, Selection::NotSelected);
+ textinput.adjust_horizontal(2, Selection::Selected);
+ let (begin, end) = textinput.get_sorted_selection();
+ assert_eq!(begin.index, 2);
+ assert_eq!(end.index, 4);
+
+ textinput.clear_selection();
+
+ textinput.adjust_horizontal(-2, Selection::Selected);
+ let (begin, end) = textinput.get_sorted_selection();
+ assert_eq!(begin.index, 2);
+ assert_eq!(end.index, 4);
+}
+
+#[test]
+fn test_textinput_replace_selection() {
+ let mut textinput = TextInput::new(Lines::Single, "abcdefg".into_string());
+ textinput.adjust_horizontal(2, Selection::NotSelected);
+ textinput.adjust_horizontal(2, Selection::Selected);
+
+ textinput.replace_selection("xyz".into_string());
+ assert_eq!(textinput.get_content().as_slice(), "abxyzefg");
+}
+
+#[test]
+fn test_textinput_current_line_length() {
+ let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".into_string());
+ assert_eq!(textinput.current_line_length(), 3);
+
+ textinput.adjust_vertical(1, Selection::NotSelected);
+ assert_eq!(textinput.current_line_length(), 2);
+
+ textinput.adjust_vertical(1, Selection::NotSelected);
+ assert_eq!(textinput.current_line_length(), 1);
+}
+
+#[test]
+fn test_textinput_adjust_vertical() {
+ let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".into_string());
+ textinput.adjust_horizontal(3, Selection::NotSelected);
+ textinput.adjust_vertical(1, Selection::NotSelected);
+ assert_eq!(textinput.edit_point.line, 1);
+ assert_eq!(textinput.edit_point.index, 2);
+
+ textinput.adjust_vertical(-1, Selection::NotSelected);
+ assert_eq!(textinput.edit_point.line, 0);
+ assert_eq!(textinput.edit_point.index, 2);
+
+ textinput.adjust_vertical(2, Selection::NotSelected);
+ assert_eq!(textinput.edit_point.line, 2);
+ assert_eq!(textinput.edit_point.index, 1);
+}
+
+#[test]
+fn test_textinput_adjust_horizontal() {
+ let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".into_string());
+ textinput.adjust_horizontal(4, Selection::NotSelected);
+ assert_eq!(textinput.edit_point.line, 1);
+ assert_eq!(textinput.edit_point.index, 0);
+
+ textinput.adjust_horizontal(1, Selection::NotSelected);
+ assert_eq!(textinput.edit_point.line, 1);
+ assert_eq!(textinput.edit_point.index, 1);
+
+ textinput.adjust_horizontal(2, Selection::NotSelected);
+ assert_eq!(textinput.edit_point.line, 2);
+ assert_eq!(textinput.edit_point.index, 0);
+
+ textinput.adjust_horizontal(-1, Selection::NotSelected);
+ assert_eq!(textinput.edit_point.line, 1);
+ assert_eq!(textinput.edit_point.index, 2);
+}
+
+#[test]
+fn test_textinput_handle_return() {
+ let mut single_line_textinput = TextInput::new(Lines::Single, "abcdef".into_string());
+ single_line_textinput.adjust_horizontal(3, Selection::NotSelected);
+ single_line_textinput.handle_return();
+ assert_eq!(single_line_textinput.get_content().as_slice(), "abcdef");
+
+ let mut multi_line_textinput = TextInput::new(Lines::Multiple, "abcdef".into_string());
+ multi_line_textinput.adjust_horizontal(3, Selection::NotSelected);
+ multi_line_textinput.handle_return();
+ assert_eq!(multi_line_textinput.get_content().as_slice(), "abc\ndef");
+}
+
+#[test]
+fn test_textinput_select_all() {
+ let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".into_string());
+ assert_eq!(textinput.edit_point.line, 0);
+ assert_eq!(textinput.edit_point.index, 0);
+
+ textinput.select_all();
+ assert_eq!(textinput.edit_point.line, 2);
+ assert_eq!(textinput.edit_point.index, 1);
+}
+
+#[test]
+fn test_textinput_get_content() {
+ let single_line_textinput = TextInput::new(Lines::Single, "abcdefg".into_string());
+ assert_eq!(single_line_textinput.get_content().as_slice(), "abcdefg");
+
+ let multi_line_textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".into_string());
+ assert_eq!(multi_line_textinput.get_content().as_slice(), "abc\nde\nf");
+}
+
+#[test]
+fn test_textinput_set_content() {
+ let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".into_string());
+ assert_eq!(textinput.get_content().as_slice(), "abc\nde\nf");
+
+ textinput.set_content("abc\nf".into_string());
+ assert_eq!(textinput.get_content().as_slice(), "abc\nf");
+
+ assert_eq!(textinput.edit_point.line, 0);
+ assert_eq!(textinput.edit_point.index, 0);
+ textinput.adjust_horizontal(3, Selection::Selected);
+ assert_eq!(textinput.edit_point.line, 0);
+ assert_eq!(textinput.edit_point.index, 3);
+ textinput.set_content("de".into_string());
+ assert_eq!(textinput.get_content().as_slice(), "de");
+ assert_eq!(textinput.edit_point.line, 0);
+ // FIXME: https://github.com/servo/servo/issues/4622.
+ assert_eq!(textinput.edit_point.index, 1);
+}
+
diff --git a/components/script/timers.rs b/components/script/timers.rs
index c9a5495b30d..9c6ec47ffef 100644
--- a/components/script/timers.rs
+++ b/components/script/timers.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::cell::DOMRefCell;
-use dom::bindings::callback::ExceptionHandling::ReportExceptions;
+use dom::bindings::callback::ExceptionHandling::Report;
use dom::bindings::codegen::Bindings::FunctionBinding::Function;
use dom::bindings::js::JSRef;
use dom::bindings::utils::Reflectable;
@@ -189,7 +189,7 @@ impl TimerManager {
// TODO: Must handle rooting of funval and args when movable GC is turned on
match data.callback {
TimerCallback::FunctionTimerCallback(function) => {
- let _ = function.Call_(this, data.args, ReportExceptions);
+ let _ = function.Call_(this, data.args, Report);
}
TimerCallback::StringTimerCallback(code_str) => {
this.evaluate_js_on_global_with_result(code_str.as_slice());