aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py95
-rw-r--r--components/script/dom/document.rs8
-rw-r--r--components/script/dom/htmloptionelement.rs21
-rw-r--r--components/script/dom/htmlselectelement.rs60
4 files changed, 180 insertions, 4 deletions
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py
index 36921feafe7..51a4653279f 100644
--- a/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/components/script/dom/bindings/codegen/CodegenRust.py
@@ -1445,7 +1445,11 @@ class MethodDefiner(PropertyDefiner):
selfHostedName = "0 as *const libc::c_char"
if m.get("methodInfo", True):
identifier = m.get("nativeName", m["name"])
- jitinfo = "&%s_methodinfo" % identifier
+ # Go through an intermediate type here, because it's not
+ # easy to tell whether the methodinfo is a JSJitInfo or
+ # a JSTypedMethodJitInfo here. The compiler knows, though,
+ # so let it do the work.
+ jitinfo = "&%s_methodinfo as *const _ as *const JSJitInfo" % identifier
accessor = "Some(generic_method)"
else:
jitinfo = "0 as *const JSJitInfo"
@@ -3089,6 +3093,26 @@ class CGMemberJITInfo(CGThing):
slotIndex=slotIndex)
return initializer.rstrip()
+ if args is not None:
+ argTypes = "%s_argTypes" % infoName
+ args = [CGMemberJITInfo.getJSArgType(arg.type) for arg in args]
+ args.append("ArgType::ArgTypeListEnd as i32")
+ argTypesDecl = (
+ "const %s: [i32; %d] = [ %s ];\n" %
+ (argTypes, len(args), ", ".join(args)))
+ return fill(
+ """
+ $*{argTypesDecl}
+ const ${infoName}: JSTypedMethodJitInfo = JSTypedMethodJitInfo {
+ base: ${jitInfo},
+ argTypes: &${argTypes} as *const _ as *const ArgType,
+ };
+ """,
+ argTypesDecl=argTypesDecl,
+ infoName=infoName,
+ jitInfo=indent(jitInfoInitializer(True)),
+ argTypes=argTypes)
+
return ("\n"
"const %s: JSJitInfo = %s;\n"
% (infoName, jitInfoInitializer(False)))
@@ -3290,6 +3314,73 @@ class CGMemberJITInfo(CGThing):
# Different types
return "JSVAL_TYPE_UNKNOWN"
+ @staticmethod
+ def getJSArgType(t):
+ assert not t.isVoid()
+ if t.nullable():
+ # Sometimes it might return null, sometimes not
+ return "ArgType::Null as i32 | %s" % CGMemberJITInfo.getJSArgType(t.inner)
+ if t.isArray():
+ # No idea yet
+ assert False
+ if t.isSequence():
+ return "ArgType::Object as i32"
+ if t.isGeckoInterface():
+ return "ArgType::Object as i32"
+ if t.isString():
+ return "ArgType::String as i32"
+ if t.isEnum():
+ return "ArgType::String as i32"
+ if t.isCallback():
+ return "ArgType::Object as i32"
+ if t.isAny():
+ # The whole point is to return various stuff
+ return "ArgType::Any as i32"
+ if t.isObject():
+ return "ArgType::Object as i32"
+ if t.isSpiderMonkeyInterface():
+ return "ArgType::Object as i32"
+ if t.isUnion():
+ u = t.unroll()
+ type = "JSJitInfo::Null as i32" if u.hasNullableType else ""
+ return reduce(CGMemberJITInfo.getSingleArgType,
+ u.flatMemberTypes, type)
+ if t.isDictionary():
+ return "ArgType::Object as i32"
+ if t.isDate():
+ return "ArgType::Object as i32"
+ if not t.isPrimitive():
+ raise TypeError("No idea what type " + str(t) + " is.")
+ tag = t.tag()
+ if tag == IDLType.Tags.bool:
+ return "ArgType::Boolean as i32"
+ if tag in [IDLType.Tags.int8, IDLType.Tags.uint8,
+ IDLType.Tags.int16, IDLType.Tags.uint16,
+ IDLType.Tags.int32]:
+ return "ArgType::Integer as i32"
+ if tag in [IDLType.Tags.int64, IDLType.Tags.uint64,
+ IDLType.Tags.unrestricted_float, IDLType.Tags.float,
+ IDLType.Tags.unrestricted_double, IDLType.Tags.double]:
+ # These all use JS_NumberValue, which can return int or double.
+ # But TI treats "double" as meaning "int or double", so we're
+ # good to return JSVAL_TYPE_DOUBLE here.
+ return "ArgType::Double as i32"
+ if tag != IDLType.Tags.uint32:
+ raise TypeError("No idea what type " + str(t) + " is.")
+ # uint32 is sometimes int and sometimes double.
+ return "ArgType::Double as i32"
+
+ @staticmethod
+ def getSingleArgType(existingType, t):
+ type = CGMemberJITInfo.getJSArgType(t)
+ if existingType == "":
+ # First element of the list; just return its type
+ return type
+
+ if type == existingType:
+ return existingType
+ return "%s | %s" % (existingType, type)
+
def getEnumValueName(value):
# Some enum values can be empty strings. Others might have weird
@@ -5086,7 +5177,7 @@ class CGBindingRoot(CGThing):
'js::jsapi::{RootedValue, JSNativeWrapper, JSNative, JSObject, JSPropertyDescriptor}',
'js::jsapi::{RootedId, JS_InternString, RootedString, INTERNED_STRING_TO_JSID}',
'js::jsapi::{JSPropertySpec}',
- 'js::jsapi::{JSString, JSTracer, JSJitInfo, OpType, AliasSet}',
+ 'js::jsapi::{JSString, JSTracer, JSJitInfo, JSTypedMethodJitInfo, OpType, AliasSet, ArgType}',
'js::jsapi::{MutableHandle, Handle, HandleId, JSType, JSValueType}',
'js::jsapi::{SymbolCode, ObjectOpResult, HandleValueArray}',
'js::jsapi::{JSJitGetterCallArgs, JSJitSetterCallArgs, JSJitMethodCallArgs, CallArgs}',
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index a05679086e9..48806937623 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -1564,6 +1564,14 @@ impl DocumentMethods for Document {
Ok(Root::upcast(KeyboardEvent::new_uninitialized(&self.window))),
"messageevent" =>
Ok(Root::upcast(MessageEvent::new_uninitialized(GlobalRef::Window(&self.window)))),
+ "touchevent" =>
+ Ok(Root::upcast(
+ TouchEvent::new_uninitialized(&self.window,
+ &TouchList::new(&self.window, &[]),
+ &TouchList::new(&self.window, &[]),
+ &TouchList::new(&self.window, &[]),
+ )
+ )),
_ =>
Err(Error::NotSupported),
}
diff --git a/components/script/dom/htmloptionelement.rs b/components/script/dom/htmloptionelement.rs
index 60af71b6c2e..8c7dea8ac1e 100644
--- a/components/script/dom/htmloptionelement.rs
+++ b/components/script/dom/htmloptionelement.rs
@@ -14,6 +14,7 @@ use dom::document::Document;
use dom::element::{AttributeMutation, Element, IN_ENABLED_STATE};
use dom::htmlelement::HTMLElement;
use dom::htmlscriptelement::HTMLScriptElement;
+use dom::htmlselectelement::HTMLSelectElement;
use dom::node::Node;
use dom::text::Text;
use dom::virtualmethods::VirtualMethods;
@@ -51,6 +52,21 @@ impl HTMLOptionElement {
let element = HTMLOptionElement::new_inherited(localName, prefix, document);
Node::reflect_node(box element, document, HTMLOptionElementBinding::Wrap)
}
+
+ pub fn set_selectedness(&self, selected: bool) {
+ self.selectedness.set(selected);
+ }
+
+ fn pick_if_selected_and_reset(&self) {
+ if let Some(select) = self.upcast::<Node>().ancestors()
+ .filter_map(Root::downcast::<HTMLSelectElement>)
+ .next() {
+ if self.Selected() {
+ select.pick_option(self);
+ }
+ select.ask_for_reset();
+ }
+ }
}
fn collect_text(element: &Element, value: &mut DOMString) {
@@ -134,8 +150,7 @@ impl HTMLOptionElementMethods for HTMLOptionElement {
fn SetSelected(&self, selected: bool) {
self.dirtiness.set(true);
self.selectedness.set(selected);
- // FIXME: as per the spec, implement 'ask for a reset'
- // https://github.com/servo/servo/issues/7774
+ self.pick_if_selected_and_reset();
}
}
@@ -187,6 +202,8 @@ impl VirtualMethods for HTMLOptionElement {
}
self.upcast::<Element>().check_parent_disabled_state_for_option();
+
+ self.pick_if_selected_and_reset();
}
fn unbind_from_tree(&self, tree_in_doc: bool) {
diff --git a/components/script/dom/htmlselectelement.rs b/components/script/dom/htmlselectelement.rs
index f82eddf39fe..04a3d174108 100644
--- a/components/script/dom/htmlselectelement.rs
+++ b/components/script/dom/htmlselectelement.rs
@@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::attr::{Attr, AttrValue};
+use dom::bindings::codegen::Bindings::HTMLOptionElementBinding::HTMLOptionElementMethods;
use dom::bindings::codegen::Bindings::HTMLSelectElementBinding;
use dom::bindings::codegen::Bindings::HTMLSelectElementBinding::HTMLSelectElementMethods;
use dom::bindings::codegen::UnionTypes::HTMLElementOrLong;
@@ -14,6 +15,7 @@ use dom::element::{AttributeMutation, Element, IN_ENABLED_STATE};
use dom::htmlelement::HTMLElement;
use dom::htmlfieldsetelement::HTMLFieldSetElement;
use dom::htmlformelement::{FormControl, HTMLFormElement};
+use dom::htmloptionelement::HTMLOptionElement;
use dom::node::{Node, window_from_node};
use dom::validitystate::ValidityState;
use dom::virtualmethods::VirtualMethods;
@@ -46,6 +48,64 @@ impl HTMLSelectElement {
let element = HTMLSelectElement::new_inherited(localName, prefix, document);
Node::reflect_node(box element, document, HTMLSelectElementBinding::Wrap)
}
+
+ // https://html.spec.whatwg.org/multipage/#ask-for-a-reset
+ pub fn ask_for_reset(&self) {
+ if self.Multiple() {
+ return;
+ }
+
+ let mut first_enabled: Option<Root<HTMLOptionElement>> = None;
+ let mut last_selected: Option<Root<HTMLOptionElement>> = None;
+
+ let node = self.upcast::<Node>();
+ for opt in node.traverse_preorder().filter_map(Root::downcast::<HTMLOptionElement>) {
+ if opt.Selected() {
+ opt.set_selectedness(false);
+ last_selected = Some(Root::from_ref(opt.r()));
+ }
+ let element = opt.upcast::<Element>();
+ if first_enabled.is_none() && !element.get_disabled_state() {
+ first_enabled = Some(Root::from_ref(opt.r()));
+ }
+ }
+
+ if let Some(last_selected) = last_selected {
+ last_selected.set_selectedness(true);
+ } else {
+ if self.display_size() == 1 {
+ if let Some(first_enabled) = first_enabled {
+ first_enabled.set_selectedness(true);
+ }
+ }
+ }
+ }
+
+ // https://html.spec.whatwg.org/multipage/#concept-select-pick
+ pub fn pick_option(&self, picked: &HTMLOptionElement) {
+ if !self.Multiple() {
+ let node = self.upcast::<Node>();
+ let picked = picked.upcast();
+ for opt in node.traverse_preorder().filter_map(Root::downcast::<HTMLOptionElement>) {
+ if opt.upcast::<HTMLElement>() != picked {
+ opt.set_selectedness(false);
+ }
+ }
+ }
+ }
+
+ // https://html.spec.whatwg.org/multipage/#concept-select-size
+ fn display_size(&self) -> u32 {
+ if self.Size() == 0 {
+ if self.Multiple() {
+ 4
+ } else {
+ 1
+ }
+ } else {
+ self.Size()
+ }
+ }
}
impl HTMLSelectElementMethods for HTMLSelectElement {