diff options
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/bindings/codegen/CodegenRust.py | 95 | ||||
-rw-r--r-- | components/script/dom/document.rs | 8 | ||||
-rw-r--r-- | components/script/dom/htmloptionelement.rs | 21 | ||||
-rw-r--r-- | components/script/dom/htmlselectelement.rs | 60 |
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 { |