chromium/third_party/blink/renderer/build/scripts/core/style/templates/computed_style_base.cc.tmpl

{% from 'templates/macros.tmpl' import license, print_if, source_files_for_generated_file %}
{% from 'templates/fields/field.tmpl' import encode, const_ref, getter_expression, getter_method_name, setter_expression, fieldwise_debug_diff, field_invalidation_diff, group_source_expression, field_source_expression, group_getter_expression %}
{% from 'templates/fields/group.tmpl' import define_field_group_class %}
{% import 'templates/fields/derived_flag.tmpl' as derived_flag %}
{{license()}}

{{source_files_for_generated_file(template_file, input_files)}}

#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/style/computed_style_base.h"
#include "third_party/blink/renderer/core/style/content_data.h"  // For the logging operator to be visible.
#include "third_party/blink/renderer/platform/wtf/size_assertions.h"

#include <utility>

namespace blink {

// Constructor and destructor are protected so that only the parent class ComputedStyle
// can instantiate this class.
ComputedStyleBase::ComputedStyleBase() :
{% set comma = joiner(", ") %}
{% for subgroup in computed_style.subgroups %}
    {{comma()}}{{subgroup.member_name}}({{subgroup.type_name}}::Create())
{% endfor %}
{% for field in computed_style.fields|selectattr('requires_tracing') %}
    {{comma()}}{{field.name}}({{encode(field, field.default_value)}})
{% endfor %}
  {{comma()}}data_{
    {% set data_comma = joiner(", ") %}
    {% for field in computed_style.fields|rejectattr('requires_tracing') %}
    {{data_comma()}}{{encode(field, field.default_value)}} // {{field.name}}
    {% endfor %}
  }
{
}

// These const_casts are quite safe, since ComputedStyle[Base] is immutable.
ComputedStyleBase::ComputedStyleBase(const ComputedStyleBuilderBase& builder) :
  {% set comma = joiner(", ") %}
  {% for subgroup in computed_style.subgroups %}
    {{comma()}}{{subgroup.member_name}}(const_cast<{{subgroup.type_name}}*>(builder.{{subgroup.member_name}}))
   {% endfor %}
  {% for field in computed_style.fields|selectattr('requires_tracing') %}
    {{comma()}}{{field.name}}(builder.{{field.name}})
  {% endfor %}
    {{comma()}}data_(builder.data_)
  {
    // Reset derived flags:
    {% for field in computed_style.fields|selectattr('derived_from') %}
    {{derived_flag.reset_expression(field)}}
    {% endfor %}
  }

{% macro find_changed_groups(group) -%}
  {% if group_getter_expression(group) != '' %}
  if (!base::ValuesEquivalent({{group_getter_expression(group)}},
      other_style.{{group_getter_expression(group)}})) {
    output.emplace_back("{{group_getter_expression(group)}}",
        sizeof(*{{group_getter_expression(group)}}));
  }
  {% endif %}
  {% for subgroup in group.subgroups -%}
    {{find_changed_groups(subgroup)}}
  {%- endfor %}
{%- endmacro %}

Vector<std::pair<String, size_t>>
ComputedStyleBase::FindChangedGroups(const ComputedStyleBase &other_style) const {
  Vector<std::pair<String, size_t>> output;
  {{ find_changed_groups(computed_style) }}
  return output;
}

void ComputedStyleBase::Trace(Visitor* visitor) const {
  static_cast<const ComputedStyle*>(this)->TraceAfterDispatch(visitor);
}


uint64_t ComputedStyleBase::FieldInvalidationDiff(const ComputedStyle& a, const ComputedStyle& b) {
  uint64_t diff = 0u;
  {{field_invalidation_diff(computed_style)|indent(2)}}
  return diff;
}

// Derived fields:

{% for field in computed_style.all_fields|selectattr('derived_from')|sort(attribute='name') %}
// {{ field.name }}
{{ derived_flag.define_impl(field, 'ComputedStyleBase') }}
{% endfor %}

#if DCHECK_IS_ON()

String ComputedStyleBase::DebugFieldToString(DebugField field) {
  switch (field) {
  {% for field in computed_style.all_fields|sort(attribute='name') %}
   case DebugField::{{field.name}}:
     return "{{field.name}}";
  {% endfor %}
  }
}

template<typename, typename = void>
constexpr bool HasLogging {};

template<typename T>
constexpr bool HasLogging<
  T,
  std::void_t<decltype(std::stringstream() << std::declval<T>())>
> = true;

template<typename> constexpr bool IsPersistent = false;
template<typename T> constexpr bool IsPersistent<Persistent<T>> = true;

template <typename> constexpr bool IsScopedRefPtr = false;
template <typename T> constexpr bool IsScopedRefPtr<scoped_refptr<T>> = true;

template<class T>
static std::string DebugStringForField(const T& t) {
  if constexpr (std::is_same_v<T, bool>) {
    return t ? "true" : "false";
  }
  if constexpr (IsPersistent<T>) {
    if constexpr (HasLogging<typename T::PointeeType>) {
      std::stringstream ss;
      ss << *t;
      return ss.str();
    }
  }
  if constexpr (IsScopedRefPtr<T>) {
    if constexpr (HasLogging<typename T::element_type>) {
      std::stringstream ss;
      ss << *t;
      return ss.str();
    }
  }
  if constexpr (HasLogging<T>) {
    std::stringstream ss;
    ss << t;
    return ss.str();
  }
  return "<unable to print>";
}

Vector<ComputedStyleBase::DebugDiff>
ComputedStyleBase::DebugDiffFields(const ComputedStyleBase& o) const {
  Vector<DebugDiff> diff;
  {{fieldwise_debug_diff(computed_style, computed_style.all_fields)|indent(2)}}
  return diff;
}

#endif // DCHECK_IS_ON()

{% for group in computed_style.subgroups %}
{{define_field_group_class(group)}}

{% endfor %}

ComputedStyleBuilderBase::ComputedStyleBuilderBase(const ComputedStyleBase& style) :
  {% set comma = joiner(", ") %}
  {% for subgroup in computed_style.subgroups %}
  {{comma()}}{{subgroup.member_name}}(style.{{subgroup.member_name}})
  {% endfor %}
  {% for field in computed_style.fields|selectattr('requires_tracing') %}
  {{comma()}}{{field.name}}(style.{{field.name}})
  {% endfor %}
  {{comma()}}data_(style.data_)
  {}

ComputedStyleBuilderBase::ComputedStyleBuilderBase(
  const ComputedStyleBase &source_for_noninherited,
  const ComputedStyleBase &parent_style) :
  {% set comma = joiner(", ") %}
  {% for subgroup in computed_style.subgroups %}
  {{comma()}}{{subgroup.member_name}}({{group_source_expression(subgroup, 'source_for_noninherited', 'parent_style')}})
  {% endfor %}
  {% for field in computed_style.fields|selectattr('requires_tracing') %}
  {{comma()}}{{field.name}}({{field_source_expression(field, 'source_for_noninherited', 'parent_style')}})
  {% endfor %}
  {{comma()}}data_{
    {% set comma = joiner(", ") %}
    {% for field in computed_style.fields|rejectattr('requires_tracing') %}
    {{comma()}}{{field_source_expression(field, 'source_for_noninherited', 'parent_style')}}
    {% endfor %}
  }
{
  {% for subgroup in computed_style.subgroups %}
    {% if subgroup.all_fields|rejectattr("is_inherited")|list|length != 0 and
       subgroup.all_fields|selectattr("is_inherited")|list|length != 0 %}
    if (parent_style.{{subgroup.member_name}} != source_for_noninherited.{{subgroup.member_name}}) {
      // We created this object fresh ourselves, so we do not need to clone it
      // if we wish to do further changes later on.
      access_.{{subgroup.member_name}} = true;
    }
    {% endif %}
  {% endfor %}

    // The following fields have the 'reset_on_new_style' flag set, but were
    // part of groups that were copied wholesale in the initialization.
  {% for subgroup in computed_style.subgroups %}
    {% for field in subgroup.all_fields|selectattr("reset_on_new_style") %}
    if ({{getter_expression(field)}} != {{encode(field, field.default_value)}}) {
      {{setter_expression(field)}} = {{encode(field, field.default_value)}};
    }
    {% endfor %}
  {% endfor %}
}

void ComputedStyleBuilderBase::PropagateIndependentInheritedProperties(
    const ComputedStyleBase& parent_style) {
  ComputedStyleBuilderBase& builder = *this;
  {% for field in computed_style.all_fields if field.is_property and field.is_independent %}
  if ({{field.is_inherited_method_name}}())
    builder.{{setter_expression(field)}} = parent_style.{{getter_expression(field)}};
  {% endfor %}
}

} // namespace blink