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