{% 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 %}