chromium/third_party/blink/renderer/build/scripts/templates/fields/field.tmpl

{% from 'templates/macros.tmpl' import print_if %}

{% macro encode(field, value) %}
{% if field.is_bit_field -%}
static_cast<unsigned>({{value}})
{%- else -%}
{{value}}
{%- endif %}
{% endmacro %}

{% macro decode(field, value) %}
{% if field.is_bit_field -%}
static_cast<{{field.type_name}}>({{value}})
{%- else -%}
{{value}}
{%- endif %}
{% endmacro %}

{% macro getter_method_name(field) -%}
{% if 'getter' not in field.computed_style_custom_functions -%}
{{field.getter_method_name}}
{%- else -%}
{{field.internal_getter_method_name}}
{%- endif %}
{%- endmacro %}

{% macro setter_method_name(field) -%}
{% if 'setter' not in field.computed_style_custom_functions -%}
{{field.setter_method_name}}
{%- else -%}
{{field.internal_setter_method_name}}
{%- endif %}
{%- endmacro %}

{% macro resetter_method_name(field) -%}
{% if 'resetter' not in field.computed_style_custom_functions -%}
{{field.resetter_method_name}}
{%- else -%}
{{field.internal_resetter_method_name}}
{%- endif %}
{%- endmacro %}

{% macro mutable_method_name(field) -%}
{{field.internal_mutable_method_name}}
{%- endmacro %}

{% macro bitfield_prefix() -%}
  data_.
{%- endmacro %}

{% macro accessor_expression_prefix(field) -%}
{#- Top-level non-tracable fields reside in the `data_` struct. -#}
{#- Derived flags should not be prefixed here, because they must always be read
    via a function. -#}
{%- if not field.group.parent and not field.requires_tracing and not field.derived_from -%}
  {{bitfield_prefix()}}
{%- endif -%}
{%- endmacro %}

{% macro getter_expression_without_prefix(field) %}
{% for group in field.group.path_without_root() -%}
{{group.member_name}}->
{%- endfor -%}
{# Derived flags compute their value lazily, so we can not access the field directly. #}
{% if field.derived_from -%}
{{getter_method_name(field)}}()
{%- else %}
{{field.name}}
{%- endif %}
{%- endmacro %}

{% macro access_flag(group) -%}
  access_.{{group.member_name}}
{%- endmacro %}

{#
  Generates nested calls to Access in preparation of modifying a field.

  Example: accessing the group of the 'baseline_shift_' field:

    Access(Access(svg_data_, access_.svg_data_)->misc_data_, access_.misc_data_)->baseline_shift_
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#}
{% macro nested_group_access(group) %}
{% if group.parent.name -%}
Access({{nested_group_access(group.parent)}}->{{group.member_name}}, {{access_flag(group)}})
{%- else -%}
Access({{group.member_name}}, {{access_flag(group)}})
{%- endif -%}
{%- endmacro %}

{% macro setter_expression_without_prefix(field) %}
{% if field.group.name -%}
{{nested_group_access(field.group)}}->
{%- endif -%}
{{field.name}}
{%- endmacro %}

{% macro getter_expression(field) %}
{{accessor_expression_prefix(field)}}{{getter_expression_without_prefix(field)}}
{%- endmacro %}

{% macro setter_expression(field) %}
{{accessor_expression_prefix(field)}}{{setter_expression_without_prefix(field)}}
{%- endmacro %}

{% macro set_if_changed(field, value) %}
{% if field.group.name -%}
if (!({{getter_expression(field)}} == {{value}}))
  {{setter_expression(field)}} = {{value}};
{%- else -%}
{{accessor_expression_prefix(field)}}{{field.name}} = {{value}};
{%- endif %}
{% endmacro %}

{% macro move_if_changed(field, value) %}
{% if field.group.name -%}
if (!({{getter_expression(field)}} == {{value}}))
  {{setter_expression(field)}} = std::move({{value}});
{%- else -%}
{{accessor_expression_prefix(field)}}{{field.name}} = std::move({{value}});
{%- endif %}
{% endmacro %}

{% macro nonconst_ref(field) %}
{% if field.is_bit_field or field.field_template == 'primitive' -%}
{{field.type_name}}
{%- else -%}
{{field.type_name}}&
{%- endif %}
{% endmacro %}

{% macro const_ref(field) %}
{% if field.is_bit_field or field.field_template == 'primitive' -%}
{{field.type_name}}
{%- else -%}
const {{field.type_name}}&
{%- endif %}
{% endmacro %}

{% macro rvalue_ref(field) -%}
{{field.type_name}}&&
{%- endmacro %}

{% macro group_getter_expression(group) %}
{% for group in group.path_without_root() -%}
{{group.member_name}}{{print_if(not loop.last, "->")}}
{%- endfor -%}
{% endmacro %}

{% macro declare_storage(field) %}
{% if field.is_bit_field %}
{{print_if(field.mutable, "mutable ")}}unsigned {{field.name}} : {{field.size}}; // {{field.type_name}}
{%- elif field.field_template == 'pointer' %}
{{field.wrapper_pointer_name}}<{{field.type_name}}> {{field.name}};
{%- else %}
{{field.type_name}} {{field.name}};
{%- endif %}
{% endmacro %}

{% macro compare(wrapper_pointer_name, expr, other_name) %}
{% if wrapper_pointer_name -%}
  base::ValuesEquivalent({{expr}}, {{other_name}}.{{expr}})
{%- else -%}
  {{expr}} == {{other_name}}.{{expr}}
{%- endif %}
{% endmacro %}

{# Given a group and a list of fields to compare, this generates a set of
   equality comparisons on those fields. The generated comparisons take
   advantage of group sharing. #}
{% macro fieldwise_compare(group, fields_to_compare, boolean_and=None) %}
{% set boolean_and = boolean_and or joiner('&& ') %}
{% for subgroup in group.subgroups %}
  {# If every field in this subgroup is to be compared, we can compare the
     group pointer instead. #}
  {% set group_expression = group_getter_expression(subgroup) %}
  {% if subgroup.all_fields|rejectattr("custom_compare")|reject("in", fields_to_compare)|list|length == 0 -%}
    {{boolean_and()}}base::ValuesEquivalent({{group_expression}}, o.{{group_expression}})
  {# Otherwise, we would have to recursively generate comparison operations
     on fields in the subgroup. If the objects are the same, we can skip the
     per-field comparisons. #}
  {% elif subgroup.all_fields|rejectattr("custom_compare")|select("in", fields_to_compare)|list|length > 0 -%}
    {{boolean_and()}}({{group_expression}}.Get() == o.{{group_expression}}.Get()
|| ({{fieldwise_compare(subgroup, fields_to_compare)}}))
  {% endif %}
{% endfor %}
{% for field in group.fields|rejectattr("custom_compare")|select("in", fields_to_compare) -%}
  {{boolean_and()}}{{compare(field.wrapper_pointer_name, getter_expression(field), "o")}}
{% endfor %}
{% endmacro %}

{% macro fieldwise_debug_diff(group, fields_to_compare) %}
{% for subgroup in group.subgroups %}
  {{fieldwise_debug_diff(subgroup, fields_to_compare)}}
{% endfor %}
// Group: {{group.name}}
{% for field in group.fields|rejectattr("custom_compare")|select("in", fields_to_compare) -%}
  if (!({{compare(field.wrapper_pointer_name, getter_expression(field), "o")}})) {
    DebugDiff d;
    d.field = DebugField::{{field.name}};
    d.actual = DebugStringForField({{getter_expression(field)}});
    d.correct = DebugStringForField(o.{{getter_expression(field)}});
    diff.push_back(std::move(d));
  }
{% endfor %}
{% endmacro %}

{% macro reset_group_access(group) -%}
  {{access_flag(group)}} = false;
  {% for subgroup in group.subgroups -%}
    {{reset_group_access(subgroup)}}
  {%- endfor %}
{%- endmacro %}

{#
  The `field_source_expression` and `group_source_expression` are used
  for the special two-argument constructor of ComputedStyleBuilderBase,
  and provide expressions suited to initialize the given field/group from
  one of two sources:

   - Non-inherited fields/groups are copied from `non_inherited_source`.
   - Inherited fields/groups are copied from `inherited_source`.
   - Fields with reset_on_new_style are instead set to their initial values.

  Subgroups with a mix of non-inherited and inherited fields are also
  initialized in the two-source fashion described above.
#}

{% macro field_source_expression(field, non_inherited_source, inherited_source) -%}
  {%- if field.reset_on_new_style -%}
    {{encode(field, field.default_value)}} /* {{field.name}}{{print_if(field.mutable, " (mutable)")}} */
  {%- elif field.is_inherited -%}
    {{inherited_source}}.{{accessor_expression_prefix(field)}}{{field.name}}
  {%- else -%}
    {{non_inherited_source}}.{{accessor_expression_prefix(field)}}{{field.name}}
  {%- endif -%}
{%- endmacro %}

{% macro group_source_expression(group, non_inherited_source, inherited_source) -%}
  {% set non_inherited = non_inherited_source + "." + group.member_name %}
  {% set inherited = inherited_source + "." + group.member_name %}
  {%- if group.all_fields|rejectattr("is_inherited")|list|length == 0 -%}
    {{inherited}}
  {%- elif group.all_fields|selectattr("is_inherited")|list|length == 0 -%}
    {{non_inherited}}
  {%- else -%}
    {#- Mix of non-inherited and inherited fields. -#}
    {{inherited}} == {{non_inherited}}
        ? {{inherited}}.Get()
        : MakeGarbageCollected<{{group.type_name}}>(*{{non_inherited}}, *{{inherited}})
  {%- endif -%}
{%- endmacro %}

{% macro fieldwise_pointer_compare_inherited(group, boolean_and=None) %}
{% set boolean_and = boolean_and or joiner('&& ') %}
{% for subgroup in group.subgroups %}
  {# If every field in this subgroup is inherited, we directly compare the
     group instead, delegating to operator== (with direct pointer comparison
     as a fast path). #}
  {% set group_expression = group_getter_expression(subgroup) %}
  {% if subgroup.all_fields|rejectattr("is_inherited")|list|length == 0 -%}
    {{boolean_and()}}base::ValuesEquivalent({{group_expression}}.Get(), o.{{group_expression}}.Get())
  {# Otherwise, we would have to recursively generate comparison operations
     on fields in the subgroup. #}
  {% elif subgroup.all_fields|selectattr("is_inherited")|list|length > 0 -%}
    {{boolean_and()}}(base::ValuesEquivalent({{group_expression}}.Get(), o.{{group_expression}}.Get())
|| ({{fieldwise_pointer_compare_inherited(subgroup)}}))
  {% endif %}
{% endfor %}
{% for field in group.fields if field.is_inherited -%}
  {{boolean_and()}}{{getter_expression(field)}} == o.{{getter_expression(field)}}
{% endfor %}
{% endmacro %}

{% macro diff_field(is_pointer_type, expr) %}
{% if is_pointer_type -%}
!base::ValuesEquivalent(a.{{expr}}, b.{{expr}})
{%- else -%}
a.{{expr}} != b.{{expr}}
{%- endif %}
{% endmacro %}

{% macro field_invalidation_diff(group_to_diff) %}
{% for subgroup in group_to_diff.subgroups|selectattr("needs_diff") %}
if (a.{{group_getter_expression(subgroup)}}.Get() != b.{{group_getter_expression(subgroup)}}.Get()) {
{{field_invalidation_diff(subgroup)|indent(2, true)}}
}
{% endfor %}
{% for field in group_to_diff.fields|selectattr("needs_diff") %}
if ({{diff_field(field.wrapper_pointer_name, getter_expression(field))}}) {
{% for invalidate in field.invalidate %}
  diff |= {{invalidate}};
{% endfor %}
}
{% endfor %}
{% endmacro %}