Chromium Code Reviews| Index: lib/dom/scripts/systemhtml.py |
| diff --git a/lib/dom/scripts/systemhtml.py b/lib/dom/scripts/systemhtml.py |
| index e7764e004adfb633732a8853c212cc06e4144b20..8f7582d1eafe941c740e143973a5c8383e51eb28 100644 |
| --- a/lib/dom/scripts/systemhtml.py |
| +++ b/lib/dom/scripts/systemhtml.py |
| @@ -898,13 +898,15 @@ class HtmlDart2JSClassGenerator(Dart2JSInterfaceGenerator): |
| return |
| if attribute.id != html_name: |
| - self._AddRenamingGetter(attribute, html_name) |
| - if not read_only: |
| - self._AddRenamingSetter(attribute, html_name) |
| + self._AddAttributeUsingProperties(attribute, html_name, read_only) |
| return |
| # If the attribute is shadowing, we can't generate a shadowing |
| # field (Issue 1633). |
| + # BUGBUG: _FindShadowedAttribute does not take into account the html |
|
vsm
2012/08/22 18:49:36
s/BUGBUG/TODO(sra)/
|
| + # renaming. we should be looking for another attribute that has the same |
| + # html_name. Two attributes with the same IDL name might not match if one |
| + # is renamed. |
| (super_attribute, super_attribute_interface) = self._FindShadowedAttribute(attribute, _merged_html_interfaces) |
| if super_attribute: |
| if read_only: |
| @@ -919,9 +921,14 @@ class HtmlDart2JSClassGenerator(Dart2JSInterfaceGenerator): |
| NAME=DartDomNameOfAttribute(attribute), |
| TYPE=self._NarrowOutputType(attribute.type.id)) |
| return |
| - |
| self._members_emitter.Emit('\n // Shadowing definition.') |
| - self._AddAttributeUsingProperties(attribute, read_only) |
| + self._AddAttributeUsingProperties(attribute, html_name, read_only) |
| + return |
| + |
| + # If the type has a conversion |
| + if (self._OutputConversion(attribute.type.id, attribute.id) or |
| + self._InputConversion(attribute.type.id, attribute.id)): |
| + self._AddAttributeUsingProperties(attribute, html_name, read_only) |
| return |
| output_type = self._NarrowOutputType(attribute.type.id) |
| @@ -937,26 +944,26 @@ class HtmlDart2JSClassGenerator(Dart2JSInterfaceGenerator): |
| NAME=DartDomNameOfAttribute(attribute), |
| TYPE=output_type) |
| - def _AddAttributeUsingProperties(self, attribute, read_only): |
| - self._AddGetter(attribute) |
| + def _AddAttributeUsingProperties(self, attribute, html_name, read_only): |
| + self._AddRenamingGetter(attribute, html_name) |
| if not read_only: |
| - self._AddSetter(attribute) |
| - |
| - def _AddGetter(self, attr): |
| - self._AddRenamingGetter(attr, DartDomNameOfAttribute(attr)) |
| - |
| - def _AddSetter(self, attr): |
| - self._AddRenamingSetter(attr, DartDomNameOfAttribute(attr)) |
| + self._AddRenamingSetter(attribute, html_name) |
| def _AddRenamingGetter(self, attr, html_name): |
| + conversion = self._OutputConversion(attr.type.id, attr.id) |
| + if conversion: |
| + return self._AddConvertingGetter(attr, html_name, conversion) |
| return_type = self._NarrowOutputType(attr.type.id) |
| self._members_emitter.Emit( |
| - '\n $TYPE get $(HTML_NAME)() native "return this.$NAME;";\n', |
| + '\n $TYPE get $HTML_NAME() native "return this.$NAME;";\n', |
| HTML_NAME=html_name, |
| NAME=attr.id, |
| TYPE=return_type) |
| def _AddRenamingSetter(self, attr, html_name): |
| + conversion = self._InputConversion(attr.type.id, attr.id) |
| + if conversion: |
| + return self._AddConvertingSetter(attr, html_name, conversion) |
| self._members_emitter.Emit( |
| '\n void set $HTML_NAME($TYPE value)' |
| ' native "this.$NAME = value;";\n', |
| @@ -964,6 +971,33 @@ class HtmlDart2JSClassGenerator(Dart2JSInterfaceGenerator): |
| NAME=attr.id, |
| TYPE=self._NarrowInputType(attr.type.id)) |
| + def _AddConvertingGetter(self, attr, html_name, conversion): |
| + #native_type = self._NarrowOutputType(attr.type.id) |
| + #return_type = conversion.output_type |
|
vsm
2012/08/22 18:49:36
Delete commented code.
|
| + self._members_emitter.Emit( |
| + '\n $RETURN_TYPE get $HTML_NAME() => $CONVERT(this._$(HTML_NAME));' |
| + '\n $NATIVE_TYPE get _$HTML_NAME() native "return this.$NAME;";' |
| + '\n', |
| + CONVERT=conversion.function_name, |
| + HTML_NAME=html_name, |
| + NAME=attr.id, |
| + RETURN_TYPE=conversion.output_type, |
| + NATIVE_TYPE=conversion.input_type) |
| + |
| + def _AddConvertingSetter(self, attr, html_name, conversion): |
| + self._members_emitter.Emit( |
| + '\n void set $HTML_NAME($INPUT_TYPE value) {' |
| + ' this._$HTML_NAME = $CONVERT(value); }' |
| + '\n void set _$HTML_NAME(/*$NATIVE_TYPE*/ value)' |
| + ' native "this.$NAME = value;";' |
| + '\n', |
| + CONVERT=conversion.function_name, |
| + HTML_NAME=html_name, |
| + NAME=attr.id, |
| + INPUT_TYPE=conversion.input_type, |
| + NATIVE_TYPE=conversion.output_type) |
| + |
| + |
| def AddOperation(self, info, html_name): |
| """ |
| Arguments: |
| @@ -976,6 +1010,13 @@ class HtmlDart2JSClassGenerator(Dart2JSInterfaceGenerator): |
| if info.IsStatic(): |
| return |
| + # Any conversions needed? |
| + if any(self._OperationRequiresConversions(op) for op in info.overloads): |
| + self._AddOperationWithConversions(info, html_name) |
| + else: |
| + self._AddDirectNativeOperation(info, html_name) |
| + |
| + def _AddDirectNativeOperation(self, info, html_name): |
| # Do we need a native body? |
| if html_name != info.declared_name: |
| return_type = self._NarrowOutputType(info.type_name) |
| @@ -989,6 +1030,7 @@ class HtmlDart2JSClassGenerator(Dart2JSInterfaceGenerator): |
| operation_emitter.Emit( |
| '\n' |
| + #' // @native("$NAME")\n;' |
| ' $TYPE $(HTML_NAME)($PARAMS) native "$NAME";\n') |
| else: |
| self._members_emitter.Emit( |
| @@ -999,6 +1041,155 @@ class HtmlDart2JSClassGenerator(Dart2JSInterfaceGenerator): |
| PARAMS=info.ParametersImplementationDeclaration( |
| lambda type_name: self._NarrowInputType(type_name))) |
| + def _AddOperationWithConversions(self, info, html_name): |
| + # Assert all operations have same return type. |
| + assert len(set([op.type.id for op in info.operations])) == 1 |
| + info = info.CopyAndWidenDefaultParameters() |
| + output_conversion = self._OutputConversion(info.type_name, info.declared_name) |
|
vsm
2012/08/22 18:49:36
line length
|
| + if output_conversion: |
| + return_type = output_conversion.output_type |
| + native_return_type = output_conversion.input_type |
| + else: |
| + return_type = self._NarrowInputType(info.type_name) |
| + native_return_type = return_type |
| + |
| + def InputType(type_name): |
| + conversion = self._InputConversion(type_name, info.declared_name) |
| + if conversion: |
| + return conversion.input_type |
| + else: |
| + return self._NarrowInputType(type_name) |
| + |
| + body = self._members_emitter.Emit( |
| + '\n' |
| + ' $TYPE $(HTML_NAME)($PARAMS) {\n' |
| + '$!BODY' |
| + ' }\n', |
| + TYPE=return_type, |
| + HTML_NAME=html_name, |
| + PARAMS=info.ParametersImplementationDeclaration(InputType, '_default')) |
| + |
| + argument_names = [param_info.name for param_info in info.param_infos] |
| + operations = info.operations |
| + ## DISPATCH |
| + |
| + method_version = [0] |
| + temp_version = [0] |
| + |
| + def GenerateCall(operation, argument_count, checks): |
| + if checks: |
| + (stmts_emitter, call_emitter) = body.Emit( |
| + ' if ($CHECKS) {\n$!STMTS$!CALL }\n', |
| + INDENT=' ', |
| + CHECKS=' &&\n '.join(checks)) |
| + else: |
| + (stmts_emitter, call_emitter) = body.Emit('$!A$!B', INDENT=' '); |
| + |
| + method_version[0] += 1 |
| + target = '_%s_%d' % (html_name, method_version[0]) |
| + arguments = [] |
| + target_parameters = [] |
| + for position, arg in enumerate(operation.arguments[:argument_count]): |
| + conversion = self._InputConversion(arg.type.id, operation.id) |
| + param_name = operation.arguments[position].id |
| + if conversion: |
| + temp_version[0] += 1 |
| + temp_name = '%s_%s' % (param_name, temp_version[0]) |
| + temp_type = conversion.output_type |
| + param_type = temp_type |
| + stmts_emitter.Emit( |
| + '$(INDENT)$TYPE $NAME = $CONVERT($ARG);\n', |
| + TYPE=TypeOrVar(temp_type), |
| + NAME=temp_name, |
| + CONVERT=conversion.function_name, |
| + ARG=argument_names[position]) |
| + arguments.append(temp_name) |
| + else: |
| + arguments.append(argument_names[position]) |
| + param_type = self._NarrowInputType(DartType(arg.type.id)) |
| + target_parameters.append( |
| + '%s%s' % (TypeOrNothing(param_type), param_name)) |
| + |
| + argument_list = ', '.join(arguments) |
| + call = '%s(%s)' % (target, argument_list) |
| + |
| + if output_conversion: |
| + call = '%s(%s)' % (output_conversion.function_name, call) |
| + |
| + if operation.type.id == 'void': |
| + call_emitter.Emit('$(INDENT)$CALL;\n$(INDENT)return;\n', |
| + CALL=call) |
| + else: |
| + call_emitter.Emit('$(INDENT)return $CALL;\n', CALL=call) |
| + |
| + self._members_emitter.Emit( |
| + ' $TYPE $TARGET($PARAMS) native "$NATIVE";\n', |
| + TYPE=native_return_type, |
| + TARGET=target, |
| + PARAMS=', '.join(target_parameters), |
| + NATIVE=info.declared_name) |
| + |
| + def GenerateChecksAndCall(operation, argument_count): |
| + checks = ['_default == %s' % name for name in argument_names] |
| + for i in range(0, argument_count): |
| + argument = operation.arguments[i] |
| + argument_name = argument_names[i] |
| + test_type = self._DartType(argument.type.id) |
| + if test_type in ['Dynamic', 'Object']: |
| + checks[i] = '_default != %s' % argument_name |
| + else: |
| + checks[i] = '(%s is %s || %s == null)' % ( |
| + argument_name, self._DartType(argument.type.id), argument_name) |
| + GenerateCall(operation, argument_count, checks) |
| + |
| + # TODO: Optimize the dispatch to avoid repeated checks. |
| + if len(operations) > 1: |
| + for operation in operations: |
| + for position, argument in enumerate(operation.arguments): |
| + if self._IsOptional(operation, argument): |
| + GenerateChecksAndCall(operation, position) |
| + GenerateChecksAndCall(operation, len(operation.arguments)) |
| + body.Emit(' throw "Incorrect number or type of arguments";\n'); |
| + else: |
| + operation = operations[0] |
| + argument_count = len(operation.arguments) |
| + for position, argument in list(enumerate(operation.arguments))[::-1]: |
| + if self._IsOptional(operation, argument): |
| + check = '_default != %s' % argument_names[position] |
| + # argument_count instead of position + 1 is used here to cover one |
| + # complicated case. Consider foo(x, [Optional] y, [Optional=DefaultIsNullString] z) |
| + # (as of now it's modelled after HTMLMediaElement.webkitAddKey). |
| + # y is optional in WebCore, while z is not. |
| + # In this case, if y !== _null, we'd like to emit foo(x, y, z) invocation, not |
| + # foo(x, y). |
|
vsm
2012/08/22 18:49:36
line len in this comment block
|
| + GenerateCall(operation, argument_count, [check]) |
| + argument_count = position |
| + GenerateCall(operation, argument_count, []) |
| + |
| + |
| + return |
| + |
| + def _IsOptional(self, operation, argument): |
| + return IsOptional(argument) |
| + |
| + |
| + def _OperationRequiresConversions(self, operation): |
| + return (self._OperationRequiresOutputConversion(operation) or |
| + self._OperationRequiresInputConversions(operation)) |
| + |
| + def _OperationRequiresOutputConversion(self, operation): |
| + return self._OutputConversion(operation.type.id, operation.id) |
| + |
| + def _OperationRequiresInputConversions(self, operation): |
| + return any(self._InputConversion(arg.type.id, operation.id) |
| + for arg in operation.arguments) |
| + |
| + def _OutputConversion(self, idl_type, member): |
| + return FindConversion(idl_type, 'get', self._interface.id, member) |
| + |
| + def _InputConversion(self, idl_type, member): |
| + return FindConversion(idl_type, 'set', self._interface.id, member) |
| + |
| def _HasCustomImplementation(self, member_name): |
| member_name = '%s.%s' % (self._html_interface_name, member_name) |
| return member_name in _js_custom_members |