1# Copyright (C) 2013 Google Inc. All rights reserved. 2# 3# Redistribution and use in source and binary forms, with or without 4# modification, are permitted provided that the following conditions are 5# met: 6# 7# * Redistributions of source code must retain the above copyright 8# notice, this list of conditions and the following disclaimer. 9# * Redistributions in binary form must reproduce the above 10# copyright notice, this list of conditions and the following disclaimer 11# in the documentation and/or other materials provided with the 12# distribution. 13# * Neither the name of Google Inc. nor the names of its 14# contributors may be used to endorse or promote products derived from 15# this software without specific prior written permission. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29# pylint: disable=relative-import 30"""Generate template values for attributes. 31 32Extends IdlType with property |constructor_type_name|. 33 34Design doc: http://www.chromium.org/developers/design-documents/idl-compiler 35""" 36 37import os 38import sys 39 40sys.path.append( 41 os.path.join(os.path.dirname(__file__), '..', '..', 'build', 'scripts')) 42from blinkbuild.name_style_converter import NameStyleConverter 43import idl_types 44from idl_types import inherits_interface 45from v8_globals import includes 46import v8_types 47import v8_utilities 48from v8_utilities import capitalize 49from v8_utilities import cpp_encoded_property_name 50from v8_utilities import cpp_name 51from v8_utilities import extended_attribute_value_as_list 52from v8_utilities import has_extended_attribute_value 53from v8_utilities import is_unforgeable 54from v8_utilities import scoped_name 55from v8_utilities import strip_suffix 56from v8_utilities import uncapitalize 57from blinkbuild.name_style_converter import NameStyleConverter 58 59 60def attribute_context(interface, attribute, interfaces, component_info): 61 """Creates a Jinja template context for an attribute of an interface. 62 63 Args: 64 interface: An interface which |attribute| belongs to 65 attribute: An attribute to create the context for 66 interfaces: A dict which maps an interface name to the definition 67 which can be referred if needed 68 component_info: A dict containing component wide information 69 70 Returns: 71 A Jinja template context for |attribute| 72 """ 73 74 idl_type = attribute.idl_type 75 base_idl_type = idl_type.base_type 76 extended_attributes = attribute.extended_attributes 77 78 idl_type.add_includes_for_type(extended_attributes) 79 if idl_type.enum_values: 80 includes.add('core/inspector/console_message.h') 81 includes.add('platform/heap/heap.h') 82 83 # [CheckSecurity] 84 is_cross_origin = 'CrossOrigin' in extended_attributes 85 is_check_security_for_receiver = (has_extended_attribute_value( 86 interface, 'CheckSecurity', 'Receiver') and is_cross_origin) 87 is_check_security_for_return_value = (has_extended_attribute_value( 88 attribute, 'CheckSecurity', 'ReturnValue')) 89 if is_check_security_for_receiver or is_check_security_for_return_value: 90 includes.add('bindings/core/v8/binding_security.h') 91 if is_check_security_for_return_value: 92 includes.add('core/frame/web_feature.h') 93 includes.add('platform/instrumentation/use_counter.h') 94 # [CrossOrigin] 95 if has_extended_attribute_value(attribute, 'CrossOrigin', 'Setter'): 96 includes.add('platform/bindings/v8_cross_origin_callback_info.h') 97 # [Constructor] 98 # TODO(yukishiino): Constructors are much like methods although constructors 99 # are not methods. Constructors must be data-type properties, and we can 100 # support them as a kind of methods. 101 constructor_type = idl_type.constructor_type_name if is_constructor_attribute( 102 attribute) else None 103 # [CEReactions] 104 is_ce_reactions = 'CEReactions' in extended_attributes 105 if is_ce_reactions: 106 includes.add('core/html/custom/ce_reactions_scope.h') 107 # [CustomElementCallbacks], [Reflect] 108 is_custom_element_callbacks = 'CustomElementCallbacks' in extended_attributes 109 is_reflect = 'Reflect' in extended_attributes 110 # [ReflectOnly] 111 reflect_only = extended_attribute_value_as_list(attribute, 'ReflectOnly') 112 if reflect_only: 113 reflect_only = map( 114 lambda v: cpp_content_attribute_value_name(interface, v), 115 reflect_only) 116 if is_custom_element_callbacks or is_reflect: 117 includes.add('core/html/custom/v0_custom_element_processing_stack.h') 118 # [PerWorldBindings] 119 if 'PerWorldBindings' in extended_attributes: 120 assert idl_type.is_wrapper_type or 'LogActivity' in \ 121 extended_attributes, \ 122 '[PerWorldBindings] should only be used with wrapper types: %s.%s' % \ 123 (interface.name, attribute.name) 124 # [SaveSameObject] 125 is_save_same_object = ('SameObject' in attribute.extended_attributes and 126 'SaveSameObject' in attribute.extended_attributes) 127 128 # [StringContext] 129 if idl_type.has_string_context: 130 includes.add('bindings/core/v8/generated_code_helper.h') 131 132 # [CachedAccessor] 133 is_cached_accessor = 'CachedAccessor' in extended_attributes 134 135 # [LegacyLenientSetter] 136 is_lenient_setter = 'LegacyLenientSetter' in extended_attributes 137 138 # [CachedAttribute] 139 cached_attribute_validation_method = extended_attributes.get( 140 'CachedAttribute') 141 142 keep_alive_for_gc = is_keep_alive_for_gc(interface, attribute) 143 144 does_generate_getter = (not has_custom_getter(attribute) 145 and not constructor_type) 146 does_generate_setter = ( 147 has_setter(interface, attribute) 148 and not (has_custom_setter(attribute) or is_lenient_setter)) 149 150 use_private_property_in_getter = (does_generate_getter 151 and (cached_attribute_validation_method 152 or is_save_same_object 153 or keep_alive_for_gc)) 154 use_private_property_in_setter = (does_generate_setter 155 and cached_attribute_validation_method) 156 private_property_is_shared_between_getter_and_setter = ( 157 use_private_property_in_getter and use_private_property_in_setter) 158 159 does_use_private_property = (use_private_property_in_getter 160 or use_private_property_in_setter 161 or is_cached_accessor) 162 if does_use_private_property: 163 includes.add('platform/bindings/v8_private_property.h') 164 165 # [LogActivity] 166 if 'LogActivity' in extended_attributes: 167 includes.add('platform/bindings/v8_per_context_data.h') 168 169 # [DeprecateAs], [MeasureAs] 170 deprecate_as = v8_utilities.deprecate_as(attribute) 171 measure_as = v8_utilities.measure_as(attribute, interface) 172 173 # [HighEntropy] 174 high_entropy = v8_utilities.high_entropy(attribute) 175 176 is_lazy_data_attribute = \ 177 (constructor_type and not (measure_as or deprecate_as)) or \ 178 (str(idl_type) == 'Window' and attribute.name in ('frames', 'self', 'window')) 179 180 runtime_features = component_info['runtime_enabled_features'] 181 182 internal_name = cpp_encoded_property_name(attribute) 183 184 cpp_type = idl_type.cpp_type 185 if idl_type.is_explicit_nullable: 186 cpp_type = v8_types.cpp_template_type('base::Optional', cpp_type) 187 188 context = { 189 # [ActivityLogging] 190 'activity_logging_world_list_for_getter': 191 v8_utilities.activity_logging_world_list(attribute, 'Getter'), 192 # [ActivityLogging] 193 'activity_logging_world_list_for_setter': 194 v8_utilities.activity_logging_world_list(attribute, 'Setter'), 195 # [ActivityLogging] 196 'activity_logging_world_check': 197 v8_utilities.activity_logging_world_check(attribute), 198 'cached_accessor_name': 199 'k%s%s' % (interface.name, attribute.name.capitalize()), 200 'cached_attribute_validation_method': 201 cached_attribute_validation_method, 202 'camel_case_name': 203 NameStyleConverter(internal_name).to_upper_camel_case(), 204 'constructor_type': 205 constructor_type, 206 'context_enabled_feature_name': 207 v8_utilities.context_enabled_feature_name(attribute), 208 'cpp_name': cpp_name(attribute), 209 'cpp_type': cpp_type, 210 'cpp_type_initializer': idl_type.cpp_type_initializer, 211 'deprecate_as': deprecate_as, 212 'does_generate_getter': does_generate_getter, 213 'does_generate_setter': does_generate_setter, 214 'enum_type': idl_type.enum_type, 215 'enum_values': idl_type.enum_values, 216 # [Exposed] 217 'exposed_test': 218 v8_utilities.exposed(attribute, interface), 219 'getter_has_no_side_effect': 220 has_extended_attribute_value(attribute, 'Affects', 'Nothing'), 221 'has_cross_origin_getter': 222 has_extended_attribute_value(attribute, 'CrossOrigin', None) or 223 has_extended_attribute_value(attribute, 'CrossOrigin', 'Getter'), 224 'has_cross_origin_setter': 225 has_extended_attribute_value(attribute, 'CrossOrigin', 'Setter'), 226 'has_custom_getter': has_custom_getter(attribute), 227 'has_custom_setter': has_custom_setter(attribute), 228 'has_promise_type': idl_type.name == 'Promise', 229 'has_setter': has_setter(interface, attribute), 230 'high_entropy': high_entropy, 231 'idl_type': str(idl_type), 232 'is_cached_accessor': is_cached_accessor, 233 'is_call_with_execution_context': 234 has_extended_attribute_value(attribute, 'CallWith', 'ExecutionContext'), 235 'is_call_with_script_state': 236 has_extended_attribute_value(attribute, 'CallWith', 'ScriptState'), 237 'is_ce_reactions': is_ce_reactions, 238 'is_check_security_for_receiver': is_check_security_for_receiver, 239 'is_check_security_for_return_value': 240 is_check_security_for_return_value, 241 'is_custom_element_callbacks': is_custom_element_callbacks, 242 # TODO(yukishiino): Make all DOM attributes accessor-type properties. 243 'is_data_type_property': is_data_type_property(interface, attribute), 244 'is_getter_raises_exception': # [RaisesException] 245 'RaisesException' in extended_attributes and 246 extended_attributes['RaisesException'] in (None, 'Getter'), 247 'is_keep_alive_for_gc': keep_alive_for_gc, 248 'is_lazy_data_attribute': is_lazy_data_attribute, 249 'is_lenient_setter': is_lenient_setter, 250 'is_lenient_this': 'LegacyLenientThis' in extended_attributes, 251 'is_nullable': idl_type.is_nullable, 252 'is_explicit_nullable': idl_type.is_explicit_nullable, 253 'is_named_constructor': is_named_constructor_attribute(attribute), 254 'is_partial_interface_member': 255 'PartialInterfaceImplementedAs' in extended_attributes, 256 'is_per_world_bindings': 'PerWorldBindings' in extended_attributes, 257 'is_put_forwards': 'PutForwards' in extended_attributes, 258 'is_read_only': attribute.is_read_only, 259 'is_reflect': is_reflect, 260 'is_replaceable': 'Replaceable' in attribute.extended_attributes, 261 'is_save_same_object': is_save_same_object, 262 'is_static': attribute.is_static, 263 'is_url': 'URL' in extended_attributes, 264 'is_unforgeable': is_unforgeable(attribute), 265 'measure_as': measure_as, 266 'name': attribute.name, 267 'on_instance': v8_utilities.on_instance(interface, attribute), 268 'on_interface': v8_utilities.on_interface(interface, attribute), 269 'on_prototype': v8_utilities.on_prototype(interface, attribute), 270 # [RuntimeEnabled] for origin trial 271 'origin_trial_feature_name': 272 v8_utilities.origin_trial_feature_name(attribute, runtime_features), 273 'private_property_is_shared_between_getter_and_setter': 274 private_property_is_shared_between_getter_and_setter, 275 'property_attributes': property_attributes(interface, attribute), 276 'reflect_empty': cpp_content_attribute_value_name( 277 interface, extended_attributes.get('ReflectEmpty')), 278 'reflect_invalid': cpp_content_attribute_value_name( 279 interface, extended_attributes.get('ReflectInvalid', '')), 280 'reflect_missing': cpp_content_attribute_value_name( 281 interface, extended_attributes.get('ReflectMissing')), 282 'reflect_only': reflect_only, 283 # [RuntimeEnabled] if not in origin trial 284 'runtime_enabled_feature_name': 285 v8_utilities.runtime_enabled_feature_name(attribute, runtime_features), 286 # [SecureContext] 287 'secure_context_test': v8_utilities.secure_context(attribute, interface), 288 'use_output_parameter_for_result': idl_type.use_output_parameter_for_result, 289 'world_suffixes': ( 290 ['', 'ForMainWorld'] 291 if 'PerWorldBindings' in extended_attributes 292 else ['']), # [PerWorldBindings] 293 } 294 295 if not has_custom_getter(attribute): 296 getter_context(interface, attribute, context) 297 if not has_custom_setter(attribute) and has_setter(interface, attribute): 298 setter_context(interface, attribute, interfaces, context) 299 300 # [RuntimeCallStatsCounter] 301 runtime_call_stats_context(interface, attribute, context) 302 303 # [CrossOrigin] is incompatible with a number of other attributes, so check 304 # for them here. 305 if is_cross_origin: 306 if context['has_cross_origin_setter'] and context['has_custom_setter']: 307 raise Exception( 308 '[CrossOrigin] and [Custom] are incompatible on the same setter: %s.%s', 309 interface.name, attribute.name) 310 if context['is_per_world_bindings']: 311 raise Exception( 312 '[CrossOrigin] and [PerWorldBindings] are incompatible: %s.%s', 313 interface.name, attribute.name) 314 if context['constructor_type']: 315 raise Exception( 316 '[CrossOrigin] cannot be used for constructors: %s.%s', 317 interface.name, attribute.name) 318 319 return context 320 321 322def runtime_call_stats_context(interface, attribute, context): 323 includes.add('platform/bindings/runtime_call_stats.h') 324 generic_counter_name = ( 325 'Blink_' + v8_utilities.cpp_name(interface) + '_' + attribute.name) 326 (counter, extended_attribute_defined) = v8_utilities.rcs_counter_name( 327 attribute, generic_counter_name) 328 runtime_call_stats = { 329 'extended_attribute_defined': 330 extended_attribute_defined, 331 'getter_counter': 332 '%s_Getter' % counter, 333 'setter_counter': 334 '%s_Setter' % counter, 335 'constructor_getter_callback_counter': 336 '%s_ConstructorGetterCallback' % generic_counter_name, 337 } 338 context.update({'runtime_call_stats': runtime_call_stats}) 339 340 341def is_origin_trial_enabled(attribute): 342 return bool(attribute['origin_trial_feature_name']) 343 344 345def is_secure_context(attribute): 346 return bool(attribute['secure_context_test']) 347 348 349def filter_accessors(attributes): 350 return [ 351 attribute for attribute in attributes 352 if not (attribute['exposed_test'] or is_secure_context(attribute) 353 or attribute['context_enabled_feature_name'] 354 or is_origin_trial_enabled(attribute) 355 or attribute['runtime_enabled_feature_name']) 356 and not attribute['is_data_type_property'] 357 ] 358 359 360def is_data_attribute(attribute): 361 return (not (attribute['exposed_test'] or is_secure_context(attribute) 362 or attribute['context_enabled_feature_name'] 363 or is_origin_trial_enabled(attribute) 364 or attribute['runtime_enabled_feature_name']) 365 and attribute['is_data_type_property']) 366 367 368def filter_data_attributes(attributes): 369 return [ 370 attribute for attribute in attributes if is_data_attribute(attribute) 371 ] 372 373 374def filter_runtime_enabled(attributes): 375 return [ 376 attribute for attribute in attributes 377 if not (attribute['exposed_test'] or is_secure_context(attribute)) 378 and attribute['runtime_enabled_feature_name'] 379 ] 380 381 382def filter_conditionally_enabled(attributes): 383 return [ 384 attribute for attribute in attributes 385 if attribute['exposed_test'] or (is_secure_context( 386 attribute) and not is_origin_trial_enabled(attribute)) 387 ] 388 389 390################################################################################ 391# Getter 392################################################################################ 393 394 395def getter_context(interface, attribute, context): 396 idl_type = attribute.idl_type 397 base_idl_type = idl_type.base_type 398 extended_attributes = attribute.extended_attributes 399 400 cpp_value = getter_expression(interface, attribute, context) 401 # Normally we can inline the function call into the return statement to 402 # avoid the overhead of using a Ref<> temporary, but for some cases 403 # (nullable types, EventHandler, [CachedAttribute], or if there are 404 # exceptions), we need to use a local variable. 405 # FIXME: check if compilers are smart enough to inline this, and if so, 406 # always use a local variable (for readability and CG simplicity). 407 if (idl_type.is_explicit_nullable or base_idl_type == 'EventHandler' 408 or 'CachedAttribute' in extended_attributes 409 or 'ReflectOnly' in extended_attributes 410 or context['is_keep_alive_for_gc'] 411 or context['is_getter_raises_exception'] 412 or context['high_entropy'] == 'Direct'): 413 context['cpp_value_original'] = cpp_value 414 cpp_value = 'cpp_value' 415 416 def v8_set_return_value_statement(for_main_world=False): 417 if (context['is_keep_alive_for_gc'] 418 or 'CachedAttribute' in extended_attributes): 419 return 'V8SetReturnValue(info, v8_value)' 420 if idl_type.is_explicit_nullable: 421 cpp_return_value = 'cpp_value.value()' 422 if idl_type.is_frozen_array: 423 cpp_return_value = 'FreezeV8Object(ToV8(cpp_value.value(), info.Holder(), info.GetIsolate()), info.GetIsolate())' 424 return 'V8SetReturnValue(info, {})'.format(cpp_return_value) 425 return idl_type.v8_set_return_value( 426 cpp_value, 427 extended_attributes=extended_attributes, 428 script_wrappable='impl', 429 for_main_world=for_main_world, 430 is_static=attribute.is_static) 431 432 cpp_value_to_script_wrappable = cpp_value 433 if idl_type.is_array_buffer_view_or_typed_array: 434 cpp_value_to_script_wrappable += '.View()' 435 436 context.update({ 437 'cpp_value': 438 cpp_value, 439 'cpp_value_to_script_wrappable': 440 cpp_value_to_script_wrappable, 441 'cpp_value_to_v8_value': 442 idl_type.cpp_value_to_v8_value( 443 cpp_value=cpp_value, 444 creation_context='holder', 445 extended_attributes=extended_attributes), 446 'is_getter_call_with_script_state': 447 has_extended_attribute_value(attribute, 'GetterCallWith', 448 'ScriptState'), 449 'v8_set_return_value_for_main_world': 450 v8_set_return_value_statement(for_main_world=True), 451 'v8_set_return_value': 452 v8_set_return_value_statement(), 453 }) 454 455 456def getter_expression(interface, attribute, context): 457 extra_arguments = [] 458 this_getter_base_name = getter_base_name(interface, attribute, 459 extra_arguments) 460 getter_name = scoped_name(interface, attribute, this_getter_base_name) 461 462 arguments = v8_utilities.call_with_arguments( 463 attribute.extended_attributes.get('GetterCallWith') 464 or attribute.extended_attributes.get('CallWith')) 465 # Members of IDL partial interface definitions are implemented in C++ as 466 # static member functions, which for instance members (non-static members) 467 # take *impl as their first argument 468 if ('PartialInterfaceImplementedAs' in attribute.extended_attributes 469 and not attribute.is_static): 470 arguments.append('*impl') 471 arguments.extend(extra_arguments) 472 if context['is_getter_raises_exception']: 473 arguments.append('exception_state') 474 if attribute.idl_type.use_output_parameter_for_result: 475 arguments.append('result') 476 477 expression = '%s(%s)' % (getter_name, ', '.join(arguments)) 478 # Needed to handle getter expressions returning Type& as the 479 # use site for |expression| expects Type*. 480 if (attribute.idl_type.is_interface_type and len(arguments) == 0 481 and not attribute.idl_type.is_array_buffer_view_or_typed_array): 482 return 'WTF::GetPtr(%s)' % expression 483 return expression 484 485 486CONTENT_ATTRIBUTE_GETTER_NAMES = { 487 'boolean': 'FastHasAttribute', 488 'long': 'GetIntegralAttribute', 489 'unsigned long': 'GetUnsignedIntegralAttribute', 490 'Element': 'GetElementAttribute', 491} 492 493 494def getter_base_name(interface, attribute, arguments): 495 extended_attributes = attribute.extended_attributes 496 497 if 'Reflect' not in extended_attributes: 498 name = cpp_name(attribute) 499 return name if 'ImplementedAs' in extended_attributes \ 500 else uncapitalize(name) 501 502 content_attribute_name = (extended_attributes['Reflect'] 503 or attribute.name.lower()) 504 if content_attribute_name in ['class', 'id', 'name']: 505 # Special-case for performance optimization. 506 return 'Get%sAttribute' % content_attribute_name.capitalize() 507 508 arguments.append(scoped_content_attribute_name(interface, attribute)) 509 510 base_idl_type = attribute.idl_type.base_type 511 if base_idl_type in CONTENT_ATTRIBUTE_GETTER_NAMES: 512 return CONTENT_ATTRIBUTE_GETTER_NAMES[base_idl_type] 513 if 'URL' in attribute.extended_attributes: 514 return 'GetURLAttribute' 515 idl_type = attribute.idl_type 516 if idl_type.is_frozen_array: 517 return 'Get%sArrayAttribute' % idl_type.element_type 518 return 'FastGetAttribute' 519 520 521def is_keep_alive_for_gc(interface, attribute): 522 idl_type = attribute.idl_type 523 base_idl_type = idl_type.base_type 524 extended_attributes = attribute.extended_attributes 525 if attribute.is_static: 526 return False 527 if idl_type.is_array_buffer_or_view: 528 return False 529 return ( 530 # For readonly attributes, for performance reasons we keep the attribute 531 # wrapper alive while the owner wrapper is alive, because the attribute 532 # never changes. 533 ( 534 attribute.is_read_only and idl_type.is_wrapper_type and 535 # There are some exceptions, however: 536 not ( 537 # Node lifetime is managed by object grouping. 538 inherits_interface(interface.name, 'Node') 539 or inherits_interface(base_idl_type, 'Node') or 540 # A self-reference is unnecessary. 541 attribute.name == 'self' or 542 # FIXME: Remove these hard-coded hacks. 543 base_idl_type in ['EventTarget', 'Window'] 544 or base_idl_type.startswith(('HTML', 'SVG'))))) 545 546 547################################################################################ 548# Setter 549################################################################################ 550 551 552def setter_context(interface, attribute, interfaces, context): 553 if 'PutForwards' in attribute.extended_attributes: 554 # Make sure the target interface and attribute exist. 555 target_interface_name = attribute.idl_type.base_type 556 target_attribute_name = attribute.extended_attributes['PutForwards'] 557 interface = interfaces[target_interface_name] 558 try: 559 next(candidate for candidate in interface.attributes 560 if candidate.name == target_attribute_name) 561 except StopIteration: 562 raise Exception('[PutForward] target not found:\n' 563 'Attribute "%s" is not present in interface "%s"' % 564 (target_attribute_name, target_interface_name)) 565 context['target_attribute_name'] = target_attribute_name 566 return 567 568 if ('Replaceable' in attribute.extended_attributes): 569 # Create the property, and early-return if an exception is thrown. 570 # Subsequent cleanup code may not be prepared to handle a pending 571 # exception. 572 context['cpp_setter'] = ( 573 'if (info.Holder()->CreateDataProperty(' + 574 'info.GetIsolate()->GetCurrentContext(), ' + 575 'property_name, v8_value).IsNothing())' + '\n return') 576 return 577 578 extended_attributes = attribute.extended_attributes 579 idl_type = attribute.idl_type 580 581 # [RaisesException], [RaisesException=Setter] 582 is_setter_raises_exception = ( 583 'RaisesException' in extended_attributes 584 and extended_attributes['RaisesException'] in [None, 'Setter']) 585 586 has_type_checking_interface = idl_type.is_wrapper_type 587 588 use_common_reflection_setter = False 589 # Enable use_common_reflection_setter if 590 # * extended_attributes is [CEReactions, Reflect] or 591 # [CEReactions, Reflect, RuntimeEnabled], 592 # * the type is boolean, DOMString, or DOMString?, and 593 # * the interface inherits from 'Element'. 594 if ('Reflect' in extended_attributes 595 and 'CEReactions' in extended_attributes 596 and str(idl_type) in ('boolean', 'DOMString', 'DOMString?') 597 and inherits_interface(interface.name, 'Element')): 598 if (len(extended_attributes) == 2 599 or (len(extended_attributes) == 3 600 and 'RuntimeEnabled' in extended_attributes)): 601 use_common_reflection_setter = True 602 603 context.update({ 604 'has_setter_exception_state': 605 is_setter_raises_exception or has_type_checking_interface 606 or idl_type.v8_conversion_needs_exception_state, 607 'has_type_checking_interface': 608 has_type_checking_interface, 609 'is_setter_call_with_execution_context': 610 has_extended_attribute_value(attribute, 'SetterCallWith', 611 'ExecutionContext'), 612 'is_setter_call_with_script_state': 613 has_extended_attribute_value(attribute, 'SetterCallWith', 614 'ScriptState'), 615 'is_setter_raises_exception': 616 is_setter_raises_exception, 617 'use_common_reflection_setter': 618 use_common_reflection_setter, 619 'v8_value_to_local_cpp_value': 620 idl_type.v8_value_to_local_cpp_value( 621 extended_attributes, 622 'v8_value', 623 'cpp_value', 624 code_generation_target='attribute_set'), 625 }) 626 627 # setter_expression() depends on context values we set above. 628 context['cpp_setter'] = setter_expression(interface, attribute, context) 629 630 631def setter_expression(interface, attribute, context): 632 extended_attributes = attribute.extended_attributes 633 arguments = v8_utilities.call_with_arguments( 634 extended_attributes.get('SetterCallWith') 635 or extended_attributes.get('CallWith')) 636 637 extra_arguments = [] 638 this_setter_base_name = setter_base_name(interface, attribute, 639 extra_arguments) 640 setter_name = scoped_name(interface, attribute, this_setter_base_name) 641 642 # Members of IDL partial interface definitions are implemented in C++ as 643 # static member functions, which for instance members (non-static members) 644 # take *impl as their first argument 645 if ('PartialInterfaceImplementedAs' in extended_attributes 646 and not attribute.is_static): 647 arguments.append('*impl') 648 arguments.extend(extra_arguments) 649 idl_type = attribute.idl_type 650 if idl_type.base_type in ('EventHandler', 'OnBeforeUnloadEventHandler', 651 'OnErrorEventHandler'): 652 if idl_type.base_type == 'EventHandler': 653 handler_type = 'kEventHandler' 654 elif idl_type.base_type == 'OnBeforeUnloadEventHandler': 655 handler_type = 'kOnBeforeUnloadEventHandler' 656 elif idl_type.base_type == 'OnErrorEventHandler': 657 handler_type = 'kOnErrorEventHandler' 658 arguments.append('JSEventHandler::CreateOrNull(' + 'v8_value, ' + 659 'JSEventHandler::HandlerType::' + handler_type + ')') 660 else: 661 arguments.append('cpp_value') 662 if context['is_setter_raises_exception']: 663 arguments.append('exception_state') 664 if context['use_common_reflection_setter']: 665 attr_name = scoped_content_attribute_name(interface, attribute) 666 if idl_type.base_type == 'boolean': 667 setter_name = 'V8SetReflectedBooleanAttribute' 668 arguments = [ 669 'info', 670 '"%s"' % interface.name, 671 '"%s"' % attribute.name, attr_name 672 ] 673 elif idl_type.base_type == 'DOMString': 674 if idl_type.is_nullable: 675 setter_name = 'V8SetReflectedNullableDOMStringAttribute' 676 else: 677 setter_name = 'V8SetReflectedDOMStringAttribute' 678 arguments = ['info', attr_name] 679 680 return '%s(%s)' % (setter_name, ', '.join(arguments)) 681 682 683CONTENT_ATTRIBUTE_SETTER_NAMES = { 684 'boolean': 'SetBooleanAttribute', 685 'long': 'SetIntegralAttribute', 686 'unsigned long': 'SetUnsignedIntegralAttribute', 687 'Element': 'SetElementAttribute', 688} 689 690 691def setter_base_name(interface, attribute, arguments): 692 if 'Reflect' not in attribute.extended_attributes: 693 return 'set%s' % capitalize(cpp_name(attribute)) 694 arguments.append(scoped_content_attribute_name(interface, attribute)) 695 696 base_idl_type = attribute.idl_type.base_type 697 if base_idl_type in CONTENT_ATTRIBUTE_SETTER_NAMES: 698 return CONTENT_ATTRIBUTE_SETTER_NAMES[base_idl_type] 699 idl_type = attribute.idl_type 700 if idl_type.is_frozen_array: 701 return 'Set%sArrayAttribute' % idl_type.element_type 702 return 'setAttribute' 703 704 705def scoped_content_attribute_name(interface, attribute): 706 content_attribute_name = (attribute.extended_attributes['Reflect'] 707 or attribute.name.lower()) 708 symbol_name = 'k' + NameStyleConverter( 709 content_attribute_name).to_upper_camel_case() 710 if interface.name.startswith('SVG'): 711 namespace = 'svg_names' 712 includes.add('core/svg_names.h') 713 else: 714 namespace = 'html_names' 715 includes.add('core/html_names.h') 716 return '%s::%sAttr' % (namespace, symbol_name) 717 718 719def cpp_content_attribute_value_name(interface, value): 720 if value == '': 721 return 'g_empty_atom' 722 if not value: 723 return value 724 includes.add('core/keywords.h') 725 return 'keywords::' + NameStyleConverter(value).to_enum_value() 726 727 728################################################################################ 729# Attribute configuration 730################################################################################ 731 732 733# Property descriptor's {writable: boolean} 734def is_writable(attribute): 735 return (not attribute.is_read_only or any( 736 keyword in attribute.extended_attributes 737 for keyword in ['PutForwards', 'Replaceable', 'LegacyLenientSetter'])) 738 739 740def is_data_type_property(interface, attribute): 741 return (is_constructor_attribute(attribute) 742 or 'CrossOrigin' in attribute.extended_attributes) 743 744 745# [PutForwards], [Replaceable], [LegacyLenientSetter] 746def has_setter(interface, attribute): 747 if (is_data_type_property(interface, attribute) 748 and (is_constructor_attribute(attribute) 749 or 'Replaceable' in attribute.extended_attributes)): 750 return False 751 752 return is_writable(attribute) 753 754 755# [NotEnumerable], [LegacyUnforgeable] 756def property_attributes(interface, attribute): 757 extended_attributes = attribute.extended_attributes 758 property_attributes_list = [] 759 if ('NotEnumerable' in extended_attributes 760 or is_constructor_attribute(attribute)): 761 property_attributes_list.append('v8::DontEnum') 762 if is_unforgeable(attribute): 763 property_attributes_list.append('v8::DontDelete') 764 if not is_writable(attribute): 765 property_attributes_list.append('v8::ReadOnly') 766 return property_attributes_list or ['v8::None'] 767 768 769# [Custom], [Custom=Getter] 770def has_custom_getter(attribute): 771 extended_attributes = attribute.extended_attributes 772 return ('Custom' in extended_attributes 773 and extended_attributes['Custom'] in [None, 'Getter']) 774 775 776# [Custom], [Custom=Setter] 777def has_custom_setter(attribute): 778 extended_attributes = attribute.extended_attributes 779 return (not attribute.is_read_only and 'Custom' in extended_attributes 780 and extended_attributes['Custom'] in [None, 'Setter']) 781 782 783################################################################################ 784# Constructors 785################################################################################ 786 787idl_types.IdlType.constructor_type_name = property( 788 lambda self: strip_suffix(self.base_type, 'Constructor')) 789 790 791def is_constructor_attribute(attribute): 792 return attribute.idl_type.name.endswith('Constructor') 793 794 795def is_named_constructor_attribute(attribute): 796 return attribute.idl_type.name.endswith('ConstructorConstructor') 797