| OLD | NEW |
| (Empty) | |
| 1 # This library is free software; you can redistribute it and/or |
| 2 # modify it under the terms of the GNU Library General Public |
| 3 # License as published by the Free Software Foundation; either |
| 4 # version 2 of the License, or (at your option) any later version. |
| 5 # |
| 6 # This library is distributed in the hope that it will be useful, |
| 7 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 9 # Library General Public License for more details. |
| 10 # |
| 11 # You should have received a copy of the GNU Library General Public License |
| 12 # along with this library; see the file COPYING.LIB. If not, write to |
| 13 # the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| 14 # Boston, MA 02111-1307, USA. |
| 15 # |
| 16 |
| 17 |
| 18 import os |
| 19 import os.path |
| 20 import sys |
| 21 import json |
| 22 import re |
| 23 |
| 24 import generate_bindings |
| 25 |
| 26 import pprint |
| 27 pp = pprint.PrettyPrinter(indent=2, width=80) |
| 28 |
| 29 |
| 30 _current_dir = os.path.dirname(os.path.realpath(__file__)) |
| 31 # jinja2 is in chromium's third_party directory |
| 32 sys.path.append(os.path.join(_current_dir, *([os.pardir] * 4))) |
| 33 import jinja2 |
| 34 |
| 35 |
| 36 ### basic utility |
| 37 |
| 38 def pathsplit(path): |
| 39 dirs = [] |
| 40 while True: |
| 41 (dirname, basename) = os.path.split(path) |
| 42 if basename=="": |
| 43 break |
| 44 dirs.append(basename) |
| 45 path = dirname |
| 46 dirs.reverse() |
| 47 return dirs |
| 48 |
| 49 def abs2rel(path, basedir): |
| 50 path_dirs = pathsplit(os.path.abspath(path)) |
| 51 basedir_dirs = pathsplit(os.path.abspath(basedir)) |
| 52 common_dirs = 0 |
| 53 for i in range(min(len(path_dirs), len(basedir_dirs))): |
| 54 if path_dirs[i] != basedir_dirs[i]: |
| 55 break |
| 56 common_dirs += 1 |
| 57 relpath = [] |
| 58 for i in range(len(basedir_dirs)-common_dirs): |
| 59 relpath.append("..") |
| 60 relpath.extend(path_dirs[common_dirs:]) |
| 61 return os.sep.join(relpath) |
| 62 |
| 63 def get_path(dic, keys): |
| 64 node = dic |
| 65 for key in keys: |
| 66 if key not in node: |
| 67 return None |
| 68 node = node[key] |
| 69 return node |
| 70 |
| 71 def apply_template(path_to_template, params): |
| 72 dirname, basename = os.path.split(path_to_template) |
| 73 path_to_templates = os.path.join(_current_dir, "templates") |
| 74 jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader([dirname, path
_to_templates])) |
| 75 template = jinja_env.get_template(basename) |
| 76 return template.render(params) |
| 77 |
| 78 |
| 79 |
| 80 ### subroutine for code generator |
| 81 |
| 82 def create_arguments(arguments): |
| 83 return ", ".join([argument for argument in arguments if argument]) |
| 84 |
| 85 def get_v8_class_name(interface): |
| 86 return "V8" + interface.name |
| 87 |
| 88 def get_impl_name(interface): |
| 89 implementedAs = interface.extended_attributes.get("ImplementedAs") |
| 90 if implementedAs is not None: |
| 91 return implementedAs |
| 92 return interface.name |
| 93 |
| 94 def get_conditional_string(interface_or_attribute_or_operation): |
| 95 conditional = interface_or_attribute_or_operation.extended_attributes.get("C
onditional"); |
| 96 if conditional is None: |
| 97 return "" |
| 98 else: |
| 99 operator = "" |
| 100 if "&" in operator: |
| 101 operator = "&" |
| 102 if "|" in operator: |
| 103 operator = "|" |
| 104 if operator == "": |
| 105 return "ENABLE(%s)" % conditional; |
| 106 else: |
| 107 # Avoid duplicated conditions. |
| 108 conditions = dict([(expression, True) for expression in conditional.
split(operator)]) |
| 109 return (operator + operator).join(["ENABLE(%s)" % expression for exp
ression in sorted(conditions.keys())]) |
| 110 |
| 111 def get_includes_for_type(type): |
| 112 if skip_include_header(type): |
| 113 return [] |
| 114 |
| 115 # Default includes |
| 116 includes = [] |
| 117 if type == "EventListener": |
| 118 includes.append("core/dom/EventListener.h") |
| 119 elif type == "SerializedScriptValue": |
| 120 includes.append("bindings/v8/SerializedScriptValue.h") |
| 121 elif type == "any" or is_callback_function_type(type): |
| 122 includes.append("bindings/v8/ScriptValue.h") |
| 123 else: |
| 124 includes.append("V8%s.h" % type) |
| 125 |
| 126 # Additional includes |
| 127 if type == "CSSStyleSheet": |
| 128 includes.append("core/css/CSSImportRule.h") |
| 129 |
| 130 if not is_dom_node_type(type): |
| 131 includes.append("wtf/RefCounted.h") |
| 132 includes.append("wtf/RefPtr.h") |
| 133 includes.append("wtf/GetPtr.h") |
| 134 |
| 135 print "[get_includes_for_type]", pp.pformat(includes) |
| 136 return includes |
| 137 |
| 138 def get_includes_for_parameter(parameter): |
| 139 includes = [] |
| 140 array_or_sequence_type = get_array_type(parameter.data_type) or get_sequence
_type(parameter.data_type) |
| 141 if array_or_sequence_type: |
| 142 if is_ref_ptr_type(array_or_sequence_type): |
| 143 includes += get_includes_for_type(array_or_sequence_type) |
| 144 else: |
| 145 includes += get_includes_for_type(parameter.data_type) |
| 146 return includes |
| 147 |
| 148 |
| 149 def get_includes_for_operation(operation): |
| 150 includes = get_includes_for_type(operation.data_type) |
| 151 for parameter in operation.parameters: |
| 152 includes += get_includes_for_parameter(parameter) |
| 153 return includes |
| 154 |
| 155 def link_overloaded_functions(interface): |
| 156 name_to_operations = {} |
| 157 for operation in interface.functions: |
| 158 name = operation.name |
| 159 if not name: |
| 160 operation.overloads = [] |
| 161 operation.overload_index = 0 |
| 162 continue |
| 163 if name not in name_to_operations: |
| 164 name_to_operations[name] = [] |
| 165 name_to_operations[name].append(operation) |
| 166 operation.overloads = name_to_operations[name] |
| 167 operation.overload_index = len(name_to_operations[name]) |
| 168 |
| 169 def apply_conditional(operation_or_attribute, code): |
| 170 conditional_string = get_conditional_string(operation_or_attribute) |
| 171 if conditional_string: |
| 172 wrapped_code = "#if %s\n" % conditional_string |
| 173 wrapped_code += code |
| 174 wrapped_code += "#endif // %s\n" % conditional_string |
| 175 return wrapped_code |
| 176 else: |
| 177 return code |
| 178 |
| 179 def get_namespace_for_interface(interface): |
| 180 if is_typed_array_type(interface.name): |
| 181 return "WTF" |
| 182 return "WebCore" |
| 183 |
| 184 |
| 185 ### Types |
| 186 |
| 187 # IDL type: [element's C++ type, V8 type] |
| 188 typed_arrays = { |
| 189 "ArrayBuffer": [], |
| 190 "ArrayBufferView": [], |
| 191 "Uint8Array": ["unsigned char", "v8::kExternalUnsignedByteArray"], |
| 192 "Uint8ClampedArray": ["unsigned char", "v8::kExternalPixelArray"], |
| 193 "Uint16Array": ["unsigned short", "v8::kExternalUnsignedShortArray"], |
| 194 "Uint32Array": ["unsigned int", "v8::kExternalUnsignedIntArray"], |
| 195 "Int8Array": ["signed char", "v8::kExternalByteArray"], |
| 196 "Int16Array": ["short", "v8::kExternalShortArray"], |
| 197 "Int32Array": ["int", "v8::kExternalIntArray"], |
| 198 "Float32Array": ["float", "v8::kExternalFloatArray"], |
| 199 "Float64Array": ["double", "v8::kExternalDoubleArray"], |
| 200 } |
| 201 |
| 202 primitive_types = { |
| 203 "boolean": True, |
| 204 "void": True, |
| 205 "Date": True, |
| 206 "byte": True, |
| 207 "octet": True, |
| 208 "short": True, |
| 209 "long": True, |
| 210 "long long": True, |
| 211 "unsigned short": True, |
| 212 "unsigned long": True, |
| 213 "unsigned long long": True, |
| 214 "float": True, |
| 215 "double": True, |
| 216 } |
| 217 |
| 218 enum_types = { |
| 219 } |
| 220 |
| 221 callback_function_types = { |
| 222 } |
| 223 |
| 224 non_wrapper_types = { |
| 225 "CompareHow": True, |
| 226 "DOMTimeStamp": True, |
| 227 "Dictionary": True, |
| 228 "EventListener": True, |
| 229 # FIXME: When EventTarget is an interface and not a mixin, fix this so that |
| 230 # EventTarget is treated as a wrapper type. |
| 231 "EventTarget": True, |
| 232 "MediaQueryListListener": True, |
| 233 "NodeFilter": True, |
| 234 "SerializedScriptValue": True, |
| 235 "any": True, |
| 236 } |
| 237 |
| 238 dom_node_types = { |
| 239 "Attr": True, |
| 240 "CDATASection": True, |
| 241 "CharacterData": True, |
| 242 "Comment": True, |
| 243 "Document": True, |
| 244 "DocumentFragment": True, |
| 245 "DocumentType": True, |
| 246 "Element": True, |
| 247 "Entity": True, |
| 248 "HTMLDocument": True, |
| 249 "Node": True, |
| 250 "Notation": True, |
| 251 "ProcessingInstruction": True, |
| 252 "ShadowRoot": True, |
| 253 "SVGDocument": True, |
| 254 "Text": True, |
| 255 "TestNode": True, |
| 256 } |
| 257 |
| 258 def get_sequence_type(type): |
| 259 matched = re.match("^sequence<([\w\d_\s]+)>.*", type) |
| 260 if matched: |
| 261 return matched.group(1) |
| 262 return ""; |
| 263 |
| 264 def get_array_type(type): |
| 265 matched = re.match("^([\w\d_\s]+)\[\]", type) |
| 266 if matched: |
| 267 return matched.group(1) |
| 268 return ""; |
| 269 |
| 270 def is_wrapper_type(type): |
| 271 if get_array_type(type): |
| 272 return False |
| 273 if get_sequence_type(type): |
| 274 return False |
| 275 if is_callback_function_type(type): |
| 276 return False |
| 277 if is_enum_type(type): |
| 278 return False |
| 279 if is_primitive_type(type): |
| 280 return False |
| 281 if type == "DOMString": |
| 282 return False |
| 283 return not non_wrapper_types.get(type); |
| 284 |
| 285 def is_typed_array_type(type): |
| 286 return type in typed_arrays |
| 287 |
| 288 def is_primitive_type(type): |
| 289 if type in primitive_types: |
| 290 return True |
| 291 return False |
| 292 |
| 293 def is_enum_type(type): |
| 294 if type in enum_types: |
| 295 return True |
| 296 return False |
| 297 |
| 298 def is_callback_function_type(type): |
| 299 if type in callback_function_types: |
| 300 return True |
| 301 return False |
| 302 |
| 303 def is_dom_node_type(type): |
| 304 if type in dom_node_types: |
| 305 return True |
| 306 if re.match("/^HTML.*Element$/", type): |
| 307 return True |
| 308 if re.match("/^SVG.*Element$/", type): |
| 309 return True |
| 310 return False |
| 311 |
| 312 def skip_include_header(type): |
| 313 if is_primitive_type(type): |
| 314 return True |
| 315 if is_enum_type(type): |
| 316 return True |
| 317 if is_callback_function_type(type): |
| 318 return True |
| 319 if type=="DOMString": |
| 320 return True |
| 321 return False |
| 322 |
| 323 def is_constructable(interface): |
| 324 for name in ["CustomConstructor", "Constructor", "ConstructorTemplate"]: |
| 325 if name in interface.extended_attributes: |
| 326 return True |
| 327 return False |
| 328 |
| 329 |
| 330 def has_custom_getter(extended_attributes): |
| 331 return "Custom" in extended_attributes or "CustomGetter" in extended_attribu
tes |
| 332 |
| 333 def has_custom_setter(extended_attributes): |
| 334 return "Custom" in extended_attributes or "CustomSetter" in extended_attribu
tes |
| 335 |
| 336 def has_custom_method(extended_attributes): |
| 337 return "Custom" in extended_attributes |
| 338 |
| 339 def is_constructor_template(interface, template_name): |
| 340 return interface.extended_attributes.get("ConstructorTemplate")==template_na
me |
| 341 |
| 342 def needs_opaque_root_for_gc(interface): |
| 343 for name in ["GenerateIsReachable", "CustomIsReachable"]: |
| 344 if name in interface.extended_attributes: |
| 345 return True |
| 346 return False |
| 347 |
| 348 # URL becomes url, but SetURL becomes setURL. |
| 349 def to_method_name(name): |
| 350 new_name = name[0].lower() + name[1:] |
| 351 for keyword in ["HTML", "URL", "JS", "XML", "XSLT", "CSS", ]: |
| 352 keyword_lcfirst = keyword[0].lower() + name[1:] |
| 353 new_name = re.sub("/^"+keyword_lcfirst+"/", keyword, new_name) |
| 354 |
| 355 # For HTML5 FileSystem API Flags attributes. |
| 356 # (create is widely used to instantiate an object and must be avoided.) |
| 357 new_name = re.sub("/^create$/", "isCreate", new_name) |
| 358 new_name = re.sub("/^exclusive$/", "isExclusive", new_name) |
| 359 |
| 360 return new_name |
| 361 |
| 362 # Returns the RuntimeEnabledFeatures function name that is hooked up to check if
a method/attribute is enabled. |
| 363 def get_runtime_enable_function_name(interface_or_attribute_or_function): |
| 364 # If a parameter is given (e.g. "EnabledAtRuntime=FeatureName") return the R
untimeEnabledFeatures::{FeatureName}Enabled() method. |
| 365 enabled_at_runtime = interface_or_attribute_or_function.extended_attributes.
get("EnabledAtRuntime") |
| 366 if enabled_at_runtime: |
| 367 return "RuntimeEnabledFeatures::%sEnabled" % to_method_name(enabled_at_r
untime) |
| 368 |
| 369 # Otherwise return a function named RuntimeEnabledFeatures::{methodName}Enab
led(). |
| 370 return "RuntimeEnabledFeatures::%sEnabled" % to_method_name(interface_or_att
ribute_or_function.name) |
| 371 |
| 372 def requires_custom_signature(function): |
| 373 # No signature needed for Custom function |
| 374 if has_custom_method(function.extended_attributes): |
| 375 return False |
| 376 # No signature needed for overloaded function |
| 377 if len(function.overloads) > 1: |
| 378 return False |
| 379 if function.is_static: |
| 380 return False |
| 381 # Type checking is performed in the generated code |
| 382 if function.extended_attributes.get("StrictTypeChecking"): |
| 383 return False |
| 384 for parameter in function.parameters: |
| 385 if parameter.is_optional and not parameter.extended_attributes.get("Defa
ult") or is_callback_interface(parameter.type): |
| 386 return False |
| 387 |
| 388 for parameter in function.parameters: |
| 389 if is_wrapper_type(parameter.type): |
| 390 return True |
| 391 return False |
| 392 |
| 393 def is_standard_function(interface, function): |
| 394 for key in ["Unforgeable", "EnabledAtRuntime", "EnabledPerContext", "DoNotCh
eckSignature", "NotEnumerable", "ReadOnly"]: |
| 395 if function.extended_attributes.get(key): |
| 396 return False |
| 397 if function.is_static: |
| 398 return False |
| 399 if requires_custom_signature(function): |
| 400 return False |
| 401 if function.extended_attributes.get("DoNotCheckSecurity") and interface.exte
nded_attributes.get("CheckSecurity") or interface.name == "Window": |
| 402 return False |
| 403 return True |
| 404 |
| 405 |
| 406 |
| 407 ### |
| 408 |
| 409 |
| 410 ### main |
| 411 class code_generator_v8: |
| 412 def __init__(self, document, idl_directories, dependent_idl_files, options): |
| 413 self.document = document |
| 414 self.dependent_idl_files = dependent_idl_files |
| 415 self.idl_directories = idl_directories |
| 416 self.idl_files = {} |
| 417 self.options = options |
| 418 self.header = "" |
| 419 self.implementation = "" |
| 420 self.cached_interfaces = {} |
| 421 |
| 422 enum_types = dict([ [enum["name"], enum["values"]] for enum in self.docu
ment.enumerations ]) |
| 423 # print "enum_types", pp.pformat(enum_types) |
| 424 callback_function_types = dict([ [enum["name"], enum] for enum in self.d
ocument.callback_functions ]) |
| 425 self.prepare_idl_files() |
| 426 |
| 427 def prepare_idl_files(self): |
| 428 directories = [ os.getcwd() + os.sep + directory for directory in self.i
dl_directories ] |
| 429 directories = filter(lambda path: os.path.isdir(path), directories) |
| 430 directories.append(".") |
| 431 # print "[prepare_idl_files] directories", directories |
| 432 for idl_file in self.dependent_idl_files: |
| 433 basename, ext = os.path.splitext(os.path.basename(idl_file)) |
| 434 self.idl_files[basename] = idl_file |
| 435 # print("[idl_files]", idl_files) |
| 436 for directory in directories: |
| 437 for root, dirs, files in os.walk(directory): |
| 438 for file in files: |
| 439 basename, ext = os.path.splitext(file) |
| 440 if ext==".idl": |
| 441 fullpath = root + os.sep + file |
| 442 self.idl_files[basename] = fullpath |
| 443 # for key, value in enumerate(self.idl_files): |
| 444 # print("[idl_files]", key, value) |
| 445 |
| 446 def idl_file_for_interface(self, interface_name): |
| 447 # print "[idl_file_for_interface]", interface_name, len(idl_files) |
| 448 # print("[idl_files]", idl_files) |
| 449 return self.idl_files.get(interface_name) |
| 450 |
| 451 def parse_interface(self, interface_name): |
| 452 if interface_name in self.cached_interfaces: |
| 453 self.cached_interfaces[interface_name] |
| 454 |
| 455 # Step #1: Find the IDL file associated with 'interface' |
| 456 filename = self.idl_file_for_interface(interface_name) |
| 457 if filename is None: |
| 458 raise Exception("Could NOT find IDL file for interface \"%s\"" % int
erface_name); |
| 459 |
| 460 if self.options.verbose: |
| 461 print " | |> Parsing parent IDL \"%s\" for interface \"%s\"" % (f
ilename, interface_name) |
| 462 |
| 463 # Step #2: Parse the found IDL file (in quiet mode). |
| 464 document = generate_bindings.read_pickled_idl(interface_name) |
| 465 for interface in document.interfaces: |
| 466 if interface.name == interface_name or interface.is_partial: |
| 467 self.cached_interfaces[interface_name] = interface |
| 468 return interface |
| 469 |
| 470 raise Exception("Could NOT find interface definition for %s in %s" % (in
terface_name, filename)); |
| 471 |
| 472 def for_all_parents(self, interface): |
| 473 for direct_parent_interface_name in interface.parents: |
| 474 direct_parent_interface = self.parse_interface(direct_parent_interfa
ce_name) |
| 475 yield direct_parent_interface |
| 476 for parent_interface in self.for_all_parents(direct_parent_interface
): |
| 477 yield parent_interface |
| 478 |
| 479 def inherits_interface(self, interface, interface_name): |
| 480 if interface.name == interface_name: |
| 481 return True |
| 482 for parent_interface in self.for_all_parents(self.interface): |
| 483 if parent_interface.name == interface_name: |
| 484 return True |
| 485 return False |
| 486 |
| 487 def interface_inherits_extended_attribute(self, interface, extended_attribut
e): |
| 488 if extended_attribute in interface.extended_attributes: |
| 489 return True |
| 490 for parent_interface in self.for_all_parents(interface): |
| 491 if extended_attribute in parent_interface.extended_attributes: |
| 492 return True |
| 493 return False |
| 494 |
| 495 |
| 496 def get_parameter_declaration(self, operation): |
| 497 parameters = [ "%s %s" % (self.get_native_type(parameter.data_type, used
_as_parameter=True, called_by_webcore=True), parameter.name) for parameter in op
eration.parameters ] |
| 498 return ", ".join(parameters) |
| 499 |
| 500 def get_native_to_js_value(self, type, extended_attributes, native_value, in
dent, receiver, creation_context, \ |
| 501 isolate, holder_container="", script_wrappable=""
, return_handle_type="", for_main_world_suffix="", return_value_arg=""): |
| 502 """ |
| 503 Create statement which convert native(C++) value into JS value. |
| 504 |
| 505 @param[in] type |
| 506 @param[in] extended_attributes |
| 507 @param[in] native_value |
| 508 @param[in] indent |
| 509 @param[in] receiver must contain one "%s". to return someth
ing: v8SetReturnValue(<holder_container>, %s); |
| 510 @param[in] creation_context |
| 511 @param[in] isolate |
| 512 @param[in] holder_container |
| 513 @param[in] script_wrappable |
| 514 @param[in] return_handle_type |
| 515 @param[in] for_main_world_suffix |
| 516 @param[in] return_value_arg |
| 517 """ |
| 518 def create_statement(js_value): |
| 519 return indent + receiver % js_value |
| 520 |
| 521 if not isolate: |
| 522 raise Exception("An Isolate is mandatory for native value => JS valu
e conversion.") |
| 523 |
| 524 # long long and unsigned long long are not representable in ECMAScript. |
| 525 if type == "long long" or type == "unsigned long long" or type == "DOMTi
meStamp": |
| 526 return create_statement("v8::Number::New(static_cast<double>(%s))" %
native_value) |
| 527 |
| 528 if is_primitive_type(type): |
| 529 if not (type=="float" or type=="double"): |
| 530 raise Exception("unexpected type %s" % type) |
| 531 return create_statement("v8::Number::New(%s)" % native_value) |
| 532 |
| 533 if type=="DOMString" or is_enum_type(type): |
| 534 conversion = extended_attributes.get("TreatReturnedNullStringAs") |
| 535 js_value = "" |
| 536 arguments = create_arguments([native_value, isolate, return_handle_t
ype]) |
| 537 if conversion is None: |
| 538 js_value = "v8String(%s)" % arguments |
| 539 elif conversion == "Null": |
| 540 js_value = "v8StringOrNull(%s)" % arguments |
| 541 elif conversion == "Undefined": |
| 542 js_value = "v8StringOrUndefined(%s)" % arguments |
| 543 else: |
| 544 raise Exception("Unknown value for TreatReturnedNullStringAs ext
ended attribute") |
| 545 |
| 546 # FIXME: Use safe handles |
| 547 return create_statement(js_value) |
| 548 |
| 549 # FIXME: Use safe handles |
| 550 return create_statement("toV8(%s, %s, %s)" % (native_value, creation_con
text, isolate)) |
| 551 |
| 552 def get_native_type(self, type, called_by_webcore=False, used_as_parameter=F
alse): |
| 553 """ |
| 554 Return native type corresponds to IDL type. |
| 555 @param[in] type |
| 556 @param[in] called_by_webcore |
| 557 @param[in] used_as_parameter |
| 558 """ |
| 559 print "[get_native_type]", type |
| 560 if type=="float": |
| 561 return "float" |
| 562 if type=="double": |
| 563 return "double" |
| 564 if type=="int" or type=="long" or type=="short" or type=="byte": |
| 565 return "int" |
| 566 if type=="unsigned long" or type=="unsigned int" or type=="unsigned shor
t" or type=="octet": |
| 567 return "unsigned" |
| 568 if type=="long long": |
| 569 return "long long" |
| 570 if type=="unsigned long long": |
| 571 return "unsigned long long" |
| 572 if type=="boolean": |
| 573 return "bool" |
| 574 if type=="DOMString": |
| 575 if used_as_parameter: |
| 576 if called_by_webcore: |
| 577 return "const String&" |
| 578 else: |
| 579 return "V8StringResource" |
| 580 return "String" |
| 581 # We need to check [ImplementedAs] extended attribute for wrapper types. |
| 582 if is_wrapper_type(type): |
| 583 interface = self.parse_interface(type) |
| 584 type = get_impl_name(interface) |
| 585 |
| 586 if used_as_parameter: |
| 587 if called_by_webcore: |
| 588 return type + "*" |
| 589 else: |
| 590 return "PassRefPtr<%s>" % type |
| 591 else: |
| 592 return "RefPtr<%s>" % type |
| 593 |
| 594 |
| 595 def header_files_for_interface(self, interface_name, impl_class_name): |
| 596 # print "[header_files_for_interface]", interface_name, impl_class_name |
| 597 includes = [] |
| 598 if is_typed_array_type(interface_name): |
| 599 includes.append("wtf/%s.h" % interface_name) |
| 600 elif not skip_include_header(interface_name): |
| 601 idl_filename = self.idl_file_for_interface(interface_name) |
| 602 assert idl_filename |
| 603 idlRelPath = "bindings/" + abs2rel(idl_filename, os.getcwd()) |
| 604 # print "idlRelPath", idl_filename, idlRelPath, os.getcwd() |
| 605 includes.append(os.path.dirname(idlRelPath) + os.sep + impl_class_na
me + ".h") |
| 606 print "[header_files_for_interface] result", pp.pformat(includes) |
| 607 return includes |
| 608 |
| 609 def generate_interface(self, interface): |
| 610 self.interface = interface |
| 611 |
| 612 self.common_template_parameters = { |
| 613 "conditional_if": "", |
| 614 "conditional_endif": "", |
| 615 } |
| 616 conditional_string = get_conditional_string(self.interface) |
| 617 if conditional_string != "": |
| 618 self.common_template_parameters["conditional_if"] = "#if " + conditi
onal_string |
| 619 self.common_template_parameters["conditional_endif"] = "#endif // "
+ conditional_string |
| 620 |
| 621 if self.options.no_h is None: |
| 622 if interface.is_callback: |
| 623 self.generate_callback_header() |
| 624 else: |
| 625 self.generate_header() |
| 626 |
| 627 if self.options.no_cpp is None: |
| 628 if interface.is_callback: |
| 629 self.generate_callback_implementation() |
| 630 else: |
| 631 self.generate_implementation() |
| 632 |
| 633 def write_interfaces(self): |
| 634 for interface in self.document.interfaces: |
| 635 self.generate_interface(interface) |
| 636 self.write_data() |
| 637 |
| 638 def write_data(self): |
| 639 """ |
| 640 options.output_directory |
| 641 options.output_headers_directory |
| 642 """ |
| 643 # print self.header |
| 644 if self.options.no_h is None: |
| 645 header_filename = self.options.output_headers_directory + os.sep + g
et_v8_class_name(self.interface) + ".h" |
| 646 with open(header_filename, "w") as f: |
| 647 f.write(self.header) |
| 648 |
| 649 if self.options.no_cpp is None: |
| 650 implementation_filename = self.options.output_directory + os.sep + g
et_v8_class_name(self.interface) + ".cpp" |
| 651 with open(implementation_filename, "w") as f: |
| 652 f.write(self.implementation) |
| 653 |
| 654 |
| 655 |
| 656 def generate_to_v8_converters(self, interface, v8_class_name, impl_class_nam
e_as_parameter): |
| 657 includes = [] |
| 658 code = "" |
| 659 if interface.extended_attributes.get("DoNotGenerateWrap") or interface.e
xtended_attributes.get("DoNotGenerateToV8"): |
| 660 return includes, code |
| 661 includes.append("bindings/v8/ScriptController.h") |
| 662 includes.append("core/page/Frame.h") |
| 663 # TODO..... |
| 664 return includes, code |
| 665 |
| 666 |
| 667 def generate_callback_header(self): |
| 668 impl_class_name = get_impl_name(self.interface); |
| 669 v8_class_name = get_v8_class_name(self.interface); |
| 670 |
| 671 template_parameters = self.common_template_parameters.copy() |
| 672 template_parameters.update({ |
| 673 "interface_name": self.interface.name, |
| 674 "impl_class_name": impl_class_name, |
| 675 "v8_class_name": v8_class_name, |
| 676 "includes": [ |
| 677 "bindings/v8/ActiveDOMCallback.h", |
| 678 "bindings/v8/DOMWrapperWorld.h", |
| 679 "bindings/v8/ScopedPersistent.h", |
| 680 ], |
| 681 "class_public_definitions": [], |
| 682 }) |
| 683 template_parameters["includes"].extend(self.header_files_for_interface(s
elf.interface.name, impl_class_name)) |
| 684 template_parameters["includes"].sort() |
| 685 for operation in self.interface.functions: |
| 686 code = "virtual %s %s(%s);" % (self.get_native_type(operation.data_t
ype), operation.name, self.get_parameter_declaration(operation)) |
| 687 template_parameters["class_public_definitions"].append(code) |
| 688 |
| 689 self.header = apply_template("scripts/callbackHeader.template", template
_parameters) |
| 690 |
| 691 def generate_callback_implementation(self): |
| 692 # pp.pprint(self.interface) |
| 693 impl_class_name = get_impl_name(self.interface); |
| 694 v8_class_name = get_v8_class_name(self.interface); |
| 695 |
| 696 template_parameters = self.common_template_parameters.copy() |
| 697 template_parameters.update({ |
| 698 "interface_name": self.interface.name, |
| 699 "impl_class_name": impl_class_name, |
| 700 "v8_class_name": v8_class_name, |
| 701 "main_includes": [ |
| 702 v8_class_name+".h", |
| 703 ], |
| 704 "sub_includes": [ |
| 705 "core/dom/ScriptExecutionContext.h", |
| 706 "bindings/v8/V8Binding.h", |
| 707 "bindings/v8/V8Callback.h", |
| 708 "wtf/Assertions.h", |
| 709 ], |
| 710 "class_public_definitions": [], |
| 711 "web_core_definitions": [], |
| 712 }) |
| 713 |
| 714 template_parameters["interface_name"] = self.interface.name |
| 715 |
| 716 for operation in self.interface.functions: |
| 717 code = {} |
| 718 if "Custom" in operation.extended_attributes: |
| 719 continue |
| 720 template_parameters["sub_includes"] += get_includes_for_operation(op
eration) |
| 721 if operation.data_type != "boolean": |
| 722 raise Exception("We don't yet support callbacks that return non-
boolean values.") |
| 723 code["signature"] = "%s %s::%s(%s)" % (self.get_native_type(operatio
n.data_type), v8_class_name, operation.name, self.get_parameter_declaration(oper
ation)) |
| 724 |
| 725 prepare_parameter_statements = [] |
| 726 code["prepare_js_parameters"] = "" |
| 727 for parameter in operation.parameters: |
| 728 receiver = "v8::Handle<v8::Value> %sHandle = %%s;" % parameter.n
ame |
| 729 subcode = self.get_native_to_js_value(parameter.data_type, para
meter.extended_attributes, parameter.name, "", receiver, "v8::Handle<v8::Object>
()", "isolate", "") + "\n" |
| 730 subcode += "if (%sHandle.IsEmpty()) {\n" % parameter.name |
| 731 subcode += " if (!isScriptControllerTerminating())\n" |
| 732 subcode += " CRASH();\n" |
| 733 subcode += " return true;\n" |
| 734 subcode += "}\n" |
| 735 code["prepare_js_parameters"] += subcode |
| 736 prepare_parameter_statements.append(" %sHandle" % parameter.n
ame) |
| 737 |
| 738 if len(prepare_parameter_statements) > 0: |
| 739 subcode = "v8::Handle<v8::Value> argv[] = {\n"; |
| 740 subcode += ",\n".join(prepare_parameter_statements) |
| 741 subcode += "\n};"; |
| 742 code["prepare_js_parameters"] += subcode |
| 743 else: |
| 744 code["prepare_js_parameters"] += "v8::Handle<v8::Value> *argv =
0;" |
| 745 |
| 746 code["number_of_parameters"] = len(operation.parameters) |
| 747 template_parameters["web_core_definitions"].append(code) |
| 748 |
| 749 template_parameters["sub_includes"] = list(set(template_parameters["sub_
includes"])) |
| 750 template_parameters["sub_includes"].sort() |
| 751 self.implementation = apply_template("scripts/callbackImplementation.tem
plate", template_parameters) |
| 752 |
| 753 def get_internal_fields(self): |
| 754 custom_internal_fields = [] |
| 755 # Event listeners on DOM nodes are explicitly supported in the GC contro
ller. |
| 756 if not self.inherits_interface(self.interface, "Node") and self.interfac
e_inherits_extended_attribute(self.interface, "EventTarget"): |
| 757 custom_internal_fields.append("eventListenerCacheIndex") |
| 758 return custom_internal_fields |
| 759 |
| 760 def generate_header_custom_internal_field_indices(self): |
| 761 custom_internal_fields = self.get_internal_fields() |
| 762 codes = [] |
| 763 custom_field_counter = 0 |
| 764 for custom_internal_field in custom_internal_fields: |
| 765 codes.append("static const int %s = v8DefaultWrapperInternalFieldCou
nt + %d;" % (custom_internal_field, custom_field_counter)) |
| 766 custom_field_counter += 1 |
| 767 codes.append("static const int internalFieldCount = v8DefaultWrapperInte
rnalFieldCount + %d;" % custom_field_counter) |
| 768 return codes |
| 769 |
| 770 def generate_header(self): |
| 771 impl_class_name = get_impl_name(self.interface); |
| 772 v8_class_name = get_v8_class_name(self.interface); |
| 773 |
| 774 template_parameters = self.common_template_parameters.copy() |
| 775 template_parameters.update({ |
| 776 "interface_name": self.interface.name, |
| 777 "impl_class_name": impl_class_name, |
| 778 "v8_class_name": v8_class_name, |
| 779 "impl_class_name_as_parameter": self.get_native_type(self.interface.
name, used_as_parameter=True), |
| 780 "is_constructor_template_of_event": is_constructor_template(self.int
erface, "Event"), |
| 781 "needs_opaque_root_for_gc": needs_opaque_root_for_gc(self.interface)
, |
| 782 "inherits_extended_attribute_active_dom_object": self.interface_inhe
rits_extended_attribute(self.interface, "ActiveDOMObject"), |
| 783 "inherits_extended_attribute_event_target": self.interface_inherits_
extended_attribute(self.interface, "EventTarget"), |
| 784 "is_constructable": is_constructable(self.interface), |
| 785 "custom_internal_field_indices": self.generate_header_custom_interna
l_field_indices(), |
| 786 "includes": [ |
| 787 "bindings/v8/WrapperTypeInfo.h", |
| 788 "bindings/v8/V8Binding.h", |
| 789 "bindings/v8/V8DOMWrapper.h", |
| 790 ], |
| 791 "operation_definitions": [], |
| 792 "attribute_definitions": [], |
| 793 }) |
| 794 |
| 795 link_overloaded_functions(self.interface); |
| 796 |
| 797 # Ensure the IsDOMNodeType function is in sync. |
| 798 if is_dom_node_type(self.interface.name) != self.inherits_interface(self
.interface, "Node"): |
| 799 inh = self.inherits_interface(self.interface, "Node") and "INHERIT"
or "" |
| 800 dom = is_dom_node_type(self.interface.name) and "DOM" or "" |
| 801 print "[IsDOMNodeType]", dom, inh |
| 802 raise Exception("IsDOMNodeType is out of date with respect to %s" %
self.interface.name) |
| 803 |
| 804 print "Parents", pp.pformat(self.interface.parents) |
| 805 for parent_interface_name in self.interface.parents: |
| 806 # print "ADD H", parent_interface_name |
| 807 template_parameters["includes"].append("V8%s.h" % parent_interface_n
ame) |
| 808 |
| 809 # TODO Window |
| 810 |
| 811 enabled_per_context_functions = [ operation for operation in self.interf
ace.functions if operation.name and operation.extended_attributes.get("EnabledPe
rContext") ] |
| 812 enabled_per_context_attributes = [ attribute for attribute in self.inter
face.attributes if attribute.extended_attributes.get("EnabledPerContext") ] |
| 813 |
| 814 for operation in self.interface.functions: |
| 815 if not operation.name: |
| 816 continue |
| 817 if has_custom_method(operation.extended_attributes) and operation.ov
erload_index==1: |
| 818 code = "static void %sMethodCustom(const v8::FunctionCallbackInf
o<v8::Value>&);" % operation.name |
| 819 template_parameters["operation_definitions"].append(apply_condit
ional(operation, code)) |
| 820 |
| 821 for attribute in self.interface.attributes: |
| 822 if has_custom_getter(attribute.extended_attributes): |
| 823 code = "static void %sAttrGetterCustom(v8::Local<v8::String> nam
e, const v8::PropertyCallbackInfo<v8::Value>&);" % attribute.name |
| 824 template_parameters["attribute_definitions"].append(apply_condit
ional(attribute, code)) |
| 825 if has_custom_setter(attribute.extended_attributes): |
| 826 code = "static void %sAttrSetterCustom(v8::Local<v8::String> nam
e, v8::Local<v8::Value>, const v8::PropertyCallbackInfo<void>&);" % attribute.na
me |
| 827 template_parameters["attribute_definitions"].append(apply_condit
ional(attribute, code)) |
| 828 |
| 829 |
| 830 |
| 831 |
| 832 |
| 833 |
| 834 |
| 835 # TODO HasCustomConstructor |
| 836 |
| 837 # TODO GenerateHeaderNamedAndIndexedPropertyAccessors |
| 838 # TODO GenerateHeaderLegacyCall |
| 839 |
| 840 # TODO Window |
| 841 |
| 842 template_parameters["install_per_context_properties_body"] = len(enabled
_per_context_attributes) > 0 and ";" or " { }" |
| 843 template_parameters["install_per_context_prototype_properties_body"] = l
en(enabled_per_context_functions) > 0 and ";" or " { }" |
| 844 |
| 845 # TODO HTMLElement |
| 846 # TODO SVGElement |
| 847 # TODO HTMLUnknownElement |
| 848 # TODO Element |
| 849 |
| 850 no_to_v8 = "DoNotGenerateToV8" in self.interface.extended_attributes |
| 851 no_wrap = "DoNotGenerateWrap" in self.interface.extended_attributes or n
o_to_v8 |
| 852 template_parameters["wrap"] = not no_wrap |
| 853 template_parameters["custom_wrap"] = custom_wrap = "CustomToV8" in self.
interface.extended_attributes |
| 854 if no_to_v8: |
| 855 if len(list(self.for_all_parents(self.interface))) > 0: |
| 856 raise Exception("Can't suppress toV8 for subclass") |
| 857 elif no_wrap: |
| 858 if not custom_wrap: |
| 859 raise Exception("Must have custom toV8") |
| 860 template_parameters["generate_to_v8"] = True |
| 861 |
| 862 template_parameters["includes"].extend(self.header_files_for_interface(s
elf.interface.name, impl_class_name)) |
| 863 template_parameters["includes"] = list(set(template_parameters["includes
"])) |
| 864 template_parameters["includes"].sort() |
| 865 |
| 866 self.header = apply_template("scripts/header.template", template_paramet
ers) |
| 867 |
| 868 # __IMPL__ |
| 869 def generate_implementation(self): |
| 870 impl_class_name = get_impl_name(self.interface); |
| 871 v8_class_name = get_v8_class_name(self.interface); |
| 872 |
| 873 normal_functions = [] |
| 874 enabled_per_context_functions = [] |
| 875 for operation in self.interface.functions: |
| 876 if operation.name=="": |
| 877 continue |
| 878 if operation.extended_attributes.get("EnabledPerContext"): |
| 879 enabled_per_context_functions.append(operation) |
| 880 else: |
| 881 normal_functions.append(operation) |
| 882 has_callbacks = False |
| 883 for operation in normal_functions: |
| 884 # Only one table entry is needed for overloaded methods: |
| 885 if operation.overload_index > 1: |
| 886 continue |
| 887 # Don't put any nonstandard functions into this table: |
| 888 if not is_standard_function(self.interface, operation): |
| 889 continue |
| 890 has_callbacks = True |
| 891 |
| 892 |
| 893 |
| 894 inherits_extended_attribute_active_dom_object = self.interface_inherits_
extended_attribute(self.interface, "ActiveDOMObject") |
| 895 inherits_extended_attribute_event_target = self.interface_inherits_exten
ded_attribute(self.interface, "EventTarget") |
| 896 has_attributes = len(self.interface.attributes) > 0 |
| 897 impl_class_name_as_parameter = self.get_native_type(self.interface.name,
used_as_parameter=True) |
| 898 |
| 899 template_parameters = self.common_template_parameters.copy() |
| 900 template_parameters.update({ |
| 901 "interface_name": self.interface.name, |
| 902 "impl_class_name": impl_class_name, |
| 903 "v8_class_name": v8_class_name, |
| 904 "impl_class_name_as_parameter": impl_class_name_as_parameter, |
| 905 "is_constructor_template_of_event": is_constructor_template(self.int
erface, "Event"), |
| 906 "needs_opaque_root_for_gc": needs_opaque_root_for_gc(self.interface)
, |
| 907 "inherits_extended_attribute_active_dom_object": inherits_extended_a
ttribute_active_dom_object, |
| 908 "inherits_extended_attribute_event_target": inherits_extended_attrib
ute_event_target, |
| 909 "is_constructable": is_constructable(self.interface), |
| 910 "custom_internal_field_indices": self.generate_header_custom_interna
l_field_indices(), |
| 911 "namespace_for_interface": get_namespace_for_interface(self.interfac
e), |
| 912 "wrapper_type_prototype": self.interface.is_exception and "WrapperTy
peErrorPrototype" or "WrapperTypeObjectPrototype", |
| 913 "enabled_at_runtime": "EnabledAtRuntime" in self.interface.extended_
attributes, |
| 914 "enable_function": get_runtime_enable_function_name(self.interface), |
| 915 "configure_template_batched_attribute": has_attributes and v8_class_
name + "Attrs" or "0", |
| 916 "configure_template_attribute_count": has_attributes and "WTF_ARRAY_
LENGTH(%sAttrs)" % v8_class_name or "0", |
| 917 "configure_template_batched_method": has_callbacks and v8_class_name
+ "Methods" or "0", |
| 918 "configure_template_method_count": has_callbacks and "WTF_ARRAY_LENG
TH(%sMethods)" % v8_class_name or "0", |
| 919 "includes": [ |
| 920 "bindings/v8/V8Binding.h", |
| 921 "bindings/v8/V8DOMWrapper.h", |
| 922 "core/dom/ContextFeatures.h", |
| 923 "core/dom/Document.h", |
| 924 "RuntimeEnabledFeatures.h", |
| 925 "wtf/UnusedParam.h", |
| 926 ], |
| 927 "operation_definitions": [], |
| 928 "attribute_definitions": [], |
| 929 }) |
| 930 template_parameters["to_active_dom_object"] = inherits_extended_attribut
e_active_dom_object and v8_class_name + "::toActiveDOMObject" or "0" |
| 931 template_parameters["to_event_target"] = inherits_extended_attribute_eve
nt_target and v8_class_name + "::toEventTarget" or "0" |
| 932 template_parameters["root_for_gc"] = needs_opaque_root_for_gc(self.inter
face) and v8_class_name + "::opaqueRootForGC" or "0" |
| 933 |
| 934 self.generate_to_v8_converters(self.interface, v8_class_name, impl_class
_name_as_parameter) |
| 935 |
| 936 template_parameters["includes"] += get_includes_for_type(self.interface.
name) |
| 937 |
| 938 parent_class_name = "" |
| 939 parent_class_template = "" |
| 940 if len(self.interface.parents) > 0: |
| 941 parent_interface_name = self.interface.parents[0] |
| 942 parent_class_name = "V8" + parent_interface_name |
| 943 print "ADD H", parent_interface_name |
| 944 template_parameters["includes"].append("V8%s.h" % parent_interface_n
ame) |
| 945 parent_class_template = parent_class_name + "::GetTemplate(isolate,
currentWorldType)" |
| 946 |
| 947 template_parameters["parent_class_info"] = parent_class_info = parent_cl
ass_name and "&%s::info" % parent_class_name or "0" |
| 948 template_parameters["parent_class_template"] = parent_class_template |
| 949 |
| 950 template_parameters["includes"] = filter(lambda include: include != v8_c
lass_name+".h", list(set(template_parameters["includes"]))) |
| 951 template_parameters["includes"].sort() |
| 952 self.implementation = apply_template("scripts/implementation.template",
template_parameters) |
| 953 |
| 954 |
| 955 |
| 956 if __name__ == '__main__': |
| 957 # HTMLTitleElement |
| 958 doc = json.loads(""" |
| 959 {"idlDocument::callbackFunctions":[],"idlDocument::enumerations":[],"idlDocu
ment::fileName":"/mnt/hdd/chromium/src/third_party/WebKit/Source/core/html/HTMLT
itleElement.idl","idlDocument::interfaces":[{"domInterface::attributes":[{"domAt
tribute::extendedAttributes":{"TreatNullAs":"NullString"},"domAttribute::getterE
xceptions":[],"domAttribute::isNullable":null,"domAttribute::isReadOnly":null,"d
omAttribute::isStatic":null,"domAttribute::name":"text","domAttribute::setterExc
eptions":[],"domAttribute::type":"DOMString"}],"domInterface::constants":[],"dom
Interface::constructors":[],"domInterface::customConstructors":[],"domInterface:
:extendedAttributes":{},"domInterface::isCallback":null,"domInterface::isExcepti
on":null,"domInterface::isPartial":null,"domInterface::name":"HTMLTitleElement",
"domInterface::operations":[],"domInterface::parents":["HTMLElement"]}]} |
| 960 """) |
| 961 # print("HTMLTitleElement") |
| 962 # pp.pprint(doc) |
| 963 |
| 964 # VoidCallback |
| 965 doc = json.loads(""" |
| 966 {"idlDocument::callbackFunctions":[],"idlDocument::enumerations":[],"idlDocu
ment::fileName":"/mnt/hdd/chromium/src/third_party/WebKit/Source/core/html/VoidC
allback.idl","idlDocument::interfaces":[{"domInterface::attributes":[],"domInter
face::constants":[],"domInterface::constructors":[],"domInterface::customConstru
ctors":[],"domInterface::extendedAttributes":{},"domInterface::functions":[{"dom
Function::extendedAttributes":{},"domFunction::isStatic":null,"domFunction::name
":"handleEvent","domFunction::overloadedIndex":null,"domFunction::parameters":[]
,"domFunction::specials":[],"domFunction::type":"boolean"}],"domInterface::isCal
lback":1,"domInterface::isException":null,"domInterface::isPartial":null,"domInt
erface::name":"VoidCallback","domInterface::parents":[]}]} |
| 967 """) |
| 968 # print("VoidCallback") |
| 969 # pp.pprint(doc) |
| 970 |
| 971 cg = code_generator_v8(doc, ["../modules"], ["/mnt/hdd/chromium/src/third_pa
rty/WebKit/Source/core/html/VoidCallback.idl"]) |
| 972 for interface in doc["idlDocument::interfaces"]: |
| 973 cg.generate_interface(interface) |
| 974 cg.write_data() |
| 975 |
| 976 |
| 977 def test_abs2rel(a, b, ref): |
| 978 result = abs2rel(a, b) |
| 979 assert result==ref, "abs2rel(%s, %s) should be %s but actually %s" % (a,
b, ref, result) |
| 980 |
| 981 test_abs2rel("./a/b/c", ".", "a/b/c") |
| 982 test_abs2rel("/a/b/c", "/a/b/d", "../c") |
| 983 |
| 984 |
| 985 |
| 986 |
| OLD | NEW |