blob: 6e885ec468256569661f9cc5a9cf2b7cafacec80 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
{% macro apply_initial(property) %}
{% set class_name = property.name.to_upper_camel_case() %}
{% if property.style_builder_declare %}
{% if property.style_builder_generate_initial %}
void {{class_name}}::ApplyInitial(StyleResolverState& state) const {
{{(caller(property) ~ '}')}}
{% endif %}
{% endif %}
{% endmacro %}
{% macro apply_inherit(property) %}
{% set class_name = property.name.to_upper_camel_case() %}
{% if property.style_builder_declare %}
{% if property.style_builder_generate_inherit %}
void {{class_name}}::ApplyInherit(StyleResolverState& state) const {
{{(caller(property) ~ '}')}}
{% endif %}
{% endif %}
{% endmacro %}
{% macro apply_value(property) %}
{% set class_name = property.name.to_upper_camel_case() %}
{% if property.style_builder_declare %}
{% if property.style_builder_generate_value %}
void {{class_name}}::ApplyValue(StyleResolverState& state, const CSSValue& value) const {
{{(caller(property) ~ '}')}}
{% endif %}
{% endif %}
{% endmacro %}
{% macro set_value(property) %}
{%- if property.font %}
state.GetFontBuilder().{{property.setter}}
{%- else %}
state.Style()->{{property.setter}}
{%- endif %}
{% endmacro %}
{% macro convert_and_set_value(property) %}
{% if property.converter == 'CSSPrimitiveValue' %}
{{set_value(property)}}(To<CSSPrimitiveValue>(value).ConvertTo<{{property.type_name}}>());
{%- elif property.converter == 'CSSIdentifierValue' %}
{{set_value(property)}}(To<CSSIdentifierValue>(value).ConvertTo<blink::{{property.type_name}}>());
{%- elif property.converter %}
{{set_value(property)}}(StyleBuilderConverter::{{property.converter}}(state, value));
{%- endif %}
{% endmacro %}
{% macro resolve_directional_property(apply_call) %}
const CSSProperty& resolved_property =
ResolveDirectionAwareProperty(state.Style()->Direction(),
state.Style()->GetWritingMode());
DCHECK(!resolved_property.IDEquals(PropertyID()));
To<Longhand>(resolved_property).{{apply_call}};
{% endmacro %}
{% macro style_builder_functions(property) %}
{% if not property.style_builder_template %}
{% call(property) apply_initial(property) %}
{% if property.font %}
{{set_value(property)}}(FontBuilder::{{property.initial}}());
{% else %}
{{set_value(property)}}(ComputedStyleInitialValues::{{property.initial}}());
{% endif %}
{% if property.independent %}
state.Style()->{{property.is_inherited_setter}}(false);
{% endif %}
{% endcall %}
{% call(property) apply_inherit(property) %}
{% if property.font %}
{{set_value(property)}}(state.ParentFontDescription().{{property.getter}}());
{% else %}
{{set_value(property)}}(state.ParentStyle()->{{property.getter}}());
{% endif %}
{% if property.independent %}
state.Style()->{{property.is_inherited_setter}}(true);
{% endif %}
{% endcall %}
{% call(property) apply_value(property) %}
{{convert_and_set_value(property)}}
{% if property.independent %}
state.Style()->{{property.is_inherited_setter}}(false);
{% endif %}
{% endcall %}
{% elif property.style_builder_template == 'empty' %}
{% call(property) apply_initial(property) %}
// Intentionally empty.
{% endcall %}
{% call(property) apply_inherit(property) %}
// Intentionally empty.
{% endcall %}
{% call(property) apply_value(property) %}
// Intentionally empty.
{% endcall %}
{% elif property.style_builder_template == 'direction_aware' %}
{% call(property) apply_initial(property) %}
{{resolve_directional_property('ApplyInitial(state)')|indent(2, true) -}}
{% endcall %}
{% call(property) apply_inherit(property) %}
{{resolve_directional_property('ApplyInherit(state)')|indent(2, true) -}}
{% endcall %}
{% call(property) apply_value(property) %}
{{resolve_directional_property('ApplyValue(state, value)')|indent(2, true) -}}
{% endcall %}
{% elif property.style_builder_template == "auto" %}
{% set auto_getter = property.style_builder_template_args['auto_getter'] or
'HasAuto' + property.name_for_methods %}
{% set auto_setter = property.style_builder_template_args['auto_setter'] or
'SetHasAuto' + property.name_for_methods %}
{% call(property) apply_initial(property) %}
state.Style()->{{auto_setter}}();
{% endcall %}
{% call(property) apply_inherit(property) %}
if (state.ParentStyle()->{{auto_getter}}())
state.Style()->{{auto_setter}}();
else
{{set_value(property)}}(state.ParentStyle()->{{property.getter}}());
{% endcall %}
{% call(property) apply_value(property) %}
auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
if (identifier_value && identifier_value->GetValueID() == CSSValueID::kAuto)
state.Style()->{{auto_setter}}();
else
{{convert_and_set_value(property)}}
{% endcall %}
{% elif property.style_builder_template in ['border_image', 'mask_box'] %}
{% set is_mask_box = property.style_builder_template == 'mask_box' %}
{% set modifier_type = property.style_builder_template_args['modifier_type'] %}
{% set getter = 'MaskBoxImage' if is_mask_box else 'BorderImage' %}
{% set setter = 'Set' + getter %}
{% call(property) apply_initial(property) %}
const NinePieceImage& current_image = state.Style()->{{getter}}();
{# Check for equality in case we can bail out before creating a new NinePieceImage. #}
{% if modifier_type == 'Outset' %}
if (style_building_utils::BorderImageLengthMatchesAllSides(current_image.Outset(),
BorderImageLength(0)))
return;
{% elif modifier_type == 'Repeat' %}
if (current_image.HorizontalRule() == kStretchImageRule &&
current_image.VerticalRule() == kStretchImageRule)
return;
{% elif modifier_type == 'Slice' and is_mask_box %}
// Masks have a different initial value for slices. Preserve the value of 0
// for backwards compatibility.
if (current_image.Fill() == true &&
style_building_utils::LengthMatchesAllSides(current_image.ImageSlices(), Length::Fixed(0)))
return;
{% elif modifier_type == 'Slice' and not is_mask_box %}
if (current_image.Fill() == false &&
style_building_utils::LengthMatchesAllSides(current_image.ImageSlices(), Length::Percent(100)))
return;
{% elif modifier_type == 'Width' and is_mask_box %}
// Masks have a different initial value for widths. Preserve the value of
// 'auto' for backwards compatibility.
if (style_building_utils::BorderImageLengthMatchesAllSides(current_image.BorderSlices(),
BorderImageLength(Length::Auto())))
return;
{% elif modifier_type == 'Width' and not is_mask_box %}
if (style_building_utils::BorderImageLengthMatchesAllSides(current_image.BorderSlices(),
BorderImageLength(1.0)))
return;
{% endif %}
NinePieceImage image(current_image);
{% if modifier_type == 'Outset' %}
image.SetOutset(0);
{% elif modifier_type == 'Repeat' %}
image.SetHorizontalRule(kStretchImageRule);
image.SetVerticalRule(kStretchImageRule);
{% elif modifier_type == 'Slice' and is_mask_box %}
image.SetImageSlices(LengthBox({{ (['Length::Fixed(0)']*4) | join(', ') }}));
image.SetFill(true);
{% elif modifier_type == 'Slice' and not is_mask_box %}
image.SetImageSlices(LengthBox({{ (['Length::Percent(100)']*4) | join(', ') }}));
image.SetFill(false);
{% elif modifier_type == 'Width' %}
image.SetBorderSlices({{ 'Length::Auto()' if is_mask_box else '1.0' }});
{% endif %}
state.Style()->{{setter}}(image);
{% endcall %}
{% call(property) apply_inherit(property) %}
NinePieceImage image(state.Style()->{{getter}}());
{% if modifier_type == 'Outset' %}
image.CopyOutsetFrom(state.ParentStyle()->{{getter}}());
{% elif modifier_type == 'Repeat' %}
image.CopyRepeatFrom(state.ParentStyle()->{{getter}}());
{% elif modifier_type == 'Slice' %}
image.CopyImageSlicesFrom(state.ParentStyle()->{{getter}}());
{% elif modifier_type == 'Width' %}
image.CopyBorderSlicesFrom(state.ParentStyle()->{{getter}}());
{% endif %}
state.Style()->{{setter}}(image);
{% endcall %}
{% call(property) apply_value(property) %}
NinePieceImage image(state.Style()->{{getter}}());
{% if modifier_type == 'Outset' %}
image.SetOutset(CSSToStyleMap::MapNinePieceImageQuad(state, value));
{% elif modifier_type == 'Repeat' %}
CSSToStyleMap::MapNinePieceImageRepeat(state, value, image);
{% elif modifier_type == 'Slice' %}
CSSToStyleMap::MapNinePieceImageSlice(state, value, image);
{% elif modifier_type == 'Width' %}
image.SetBorderSlices(CSSToStyleMap::MapNinePieceImageQuad(state, value));
{% endif %}
state.Style()->{{setter}}(image);
{% endcall %}
{% elif property.style_builder_template in ['animation', 'transition'] %}
{% set attribute = property.style_builder_template_args['attribute'] %}
{% set animation = 'Animation' if property.style_builder_template == 'animation' else 'Transition' %}
{% set vector = attribute + "List()" %}
{% call(property) apply_initial(property) %}
if (!state.Style()->{{animation}}s())
return;
CSS{{animation}}Data& data = state.Style()->Access{{animation}}s();
data.{{vector}}.clear();
data.{{vector}}.push_back(CSS{{animation}}Data::Initial{{attribute}}());
{% endcall %}
{% call(property) apply_inherit(property) %}
const CSS{{animation}}Data* parent_data = state.ParentStyle()->{{animation}}s();
if (!parent_data)
ApplyInitial{{property_id}}(state);
else
state.Style()->Access{{animation}}s().{{vector}} = parent_data->{{vector}};
{% endcall %}
{% call(property) apply_value(property) %}
CSS{{animation}}Data& data = state.Style()->Access{{animation}}s();
data.{{vector}}.clear();
for (auto& listValue : To<CSSValueList>(value))
data.{{vector}}.push_back(CSSToStyleMap::MapAnimation{{attribute}}(*listValue));
{% endcall %}
{% elif property.style_builder_template in ['background_layer', 'mask_layer'] %}
{% set layer_type = 'Background' if property.style_builder_template == 'background_layer' else 'Mask' %}
{% set fill_type = property.style_builder_template_args['fill_type'] %}
{% set fill_type_getter = property.style_builder_template_args['fill_type_getter'] or fill_type %}
{% call(property) apply_initial(property) %}
FillLayer* curr_child = &state.Style()->Access{{layer_type}}Layers();
curr_child->Set{{fill_type}}(FillLayer::InitialFill{{fill_type}}(EFillLayerType::k{{layer_type}}));
for (curr_child = curr_child->Next(); curr_child; curr_child = curr_child->Next())
curr_child->Clear{{fill_type}}();
{% endcall %}
{% call(property) apply_inherit(property) %}
FillLayer* curr_child = &state.Style()->Access{{layer_type}}Layers();
FillLayer* prev_child = 0;
const FillLayer* curr_parent = &state.ParentStyle()->{{layer_type}}Layers();
while (curr_parent && curr_parent->Is{{fill_type}}Set()) {
if (!curr_child)
curr_child = prev_child->EnsureNext();
curr_child->Set{{fill_type}}(curr_parent->{{fill_type_getter}}());
{% if fill_type == "PositionX" %}
if (curr_parent->IsBackgroundXOriginSet())
curr_child->SetBackgroundXOrigin(curr_parent->BackgroundXOrigin());
{% endif %}
{% if fill_type == "PositionY" %}
if (curr_parent->IsBackgroundYOriginSet())
curr_child->SetBackgroundYOrigin(curr_parent->BackgroundYOrigin());
{% endif %}
prev_child = curr_child;
curr_child = prev_child->Next();
curr_parent = curr_parent->Next();
}
while (curr_child) {
// Reset any remaining layers to not have the property set.
curr_child->Clear{{fill_type}}();
curr_child = curr_child->Next();
}
{% endcall %}
{% call(property) apply_value(property) %}
FillLayer* curr_child = &state.Style()->Access{{layer_type}}Layers();
FillLayer* prev_child = 0;
const auto* value_list = DynamicTo<CSSValueList>(value);
if (value_list && !value.IsImageSetValue()) {
// Walk each value and put it into a layer, creating new layers as needed.
for (unsigned int i = 0; i < value_list->length(); i++) {
if (!curr_child)
curr_child = prev_child->EnsureNext();
CSSToStyleMap::MapFill{{fill_type}}(state, curr_child, value_list->Item(i));
prev_child = curr_child;
curr_child = curr_child->Next();
}
} else {
CSSToStyleMap::MapFill{{fill_type}}(state, curr_child, value);
curr_child = curr_child->Next();
}
while (curr_child) {
// Reset all remaining layers to not have the property set.
curr_child->Clear{{fill_type}}();
curr_child = curr_child->Next();
}
{% endcall %}
{% elif property.style_builder_template in ['color', 'visited_color'] %}
{% set initial_color = property.style_builder_template_args['initial_color'] or 'StyleColor::CurrentColor' %}
{% set is_visited = property.style_builder_template == 'visited_color' %}
{% set main_getter = is_visited and property.unvisited_property.getter or property.getter %}
{% call(property) apply_initial(property) %}
{{set_value(property)}}({{initial_color}}());
{% endcall %}
{% call(property) apply_inherit(property) %}
{{set_value(property)}}(state.ParentStyle()->{{main_getter}}());
{% endcall %}
{% call(property) apply_value(property) %}
{% set visited_link = is_visited and 'true' or 'false' %}
{{set_value(property)}}(StyleBuilderConverter::{{property.converter}}(state, value, {{visited_link}}));
{% endcall %}
{% elif property.style_builder_template == 'counter' %}
{% set action = property.style_builder_template_args['action'] %}
{% call(property) apply_initial(property) %}
state.Style()->Clear{{action}}Directives();
{% endcall %}
{% call(property) apply_inherit(property) %}
state.Style()->Clear{{action}}Directives();
const CounterDirectiveMap* parent_map = state.ParentStyle()->GetCounterDirectives();
if (!parent_map)
return;
CounterDirectiveMap& map = state.Style()->AccessCounterDirectives();
DCHECK(!parent_map->IsEmpty());
typedef CounterDirectiveMap::const_iterator Iterator;
Iterator end = parent_map->end();
for (Iterator it = parent_map->begin(); it != end; ++it) {
CounterDirectives& directives = map.insert(it->key, CounterDirectives()).stored_value->value;
directives.Inherit{{action}}(it->value);
}
{% endcall %}
{% call(property) apply_value(property) %}
state.Style()->Clear{{action}}Directives();
const auto* list = DynamicTo<CSSValueList>(value);
if (!list) {
DCHECK_EQ(To<CSSIdentifierValue>(value).GetValueID(), CSSValueID::kNone);
return;
}
CounterDirectiveMap& map = state.Style()->AccessCounterDirectives();
for (const CSSValue* item : *list) {
const auto& pair = To<CSSValuePair>(*item);
AtomicString identifier(To<CSSCustomIdentValue>(pair.First()).Value());
int counter_value = To<CSSPrimitiveValue>(pair.Second()).GetIntValue();
CounterDirectives& directives =
map.insert(identifier, CounterDirectives()).stored_value->value;
{% if action == 'Reset' %}
directives.SetResetValue(counter_value);
{% elif action == 'Increment' %}
directives.AddIncrementValue(counter_value);
{% else %}
directives.SetSetValue(counter_value);
{% endif %}
}
DCHECK(!map.IsEmpty());
{% endcall %}
{% elif property.style_builder_template == 'grid' %}
{% set type = property.style_builder_template_args['type'] %}
{% call(property) apply_initial(property) %}
state.Style()->SetGridTemplate{{type}}s(ComputedStyleInitialValues::InitialGridTemplate{{type}}s());
state.Style()->SetNamedGrid{{type}}Lines(ComputedStyleInitialValues::InitialNamedGrid{{type}}Lines());
state.Style()->SetOrderedNamedGrid{{type}}Lines(ComputedStyleInitialValues::InitialOrderedNamedGrid{{type}}Lines());
state.Style()->SetGridAutoRepeat{{type}}s(ComputedStyleInitialValues::InitialGridAutoRepeat{{type}}s());
state.Style()->SetGridAutoRepeat{{type}}sInsertionPoint(ComputedStyleInitialValues::InitialGridAutoRepeat{{type}}sInsertionPoint());
state.Style()->SetAutoRepeatNamedGrid{{type}}Lines(ComputedStyleInitialValues::InitialNamedGrid{{type}}Lines());
state.Style()->SetAutoRepeatOrderedNamedGrid{{type}}Lines(ComputedStyleInitialValues::InitialOrderedNamedGrid{{type}}Lines());
state.Style()->SetGridAutoRepeat{{type}}sType(ComputedStyleInitialValues::InitialGridAutoRepeat{{type}}sType());
{% endcall %}
{% call(property) apply_inherit(property) %}
state.Style()->SetGridTemplate{{type}}s(state.ParentStyle()->GridTemplate{{type}}s());
state.Style()->SetNamedGrid{{type}}Lines(state.ParentStyle()->NamedGrid{{type}}Lines());
state.Style()->SetOrderedNamedGrid{{type}}Lines(state.ParentStyle()->OrderedNamedGrid{{type}}Lines());
state.Style()->SetGridAutoRepeat{{type}}s(state.ParentStyle()->GridAutoRepeat{{type}}s());
state.Style()->SetGridAutoRepeat{{type}}sInsertionPoint(state.ParentStyle()->GridAutoRepeat{{type}}sInsertionPoint());
state.Style()->SetAutoRepeatNamedGrid{{type}}Lines(state.ParentStyle()->AutoRepeatNamedGrid{{type}}Lines());
state.Style()->SetAutoRepeatOrderedNamedGrid{{type}}Lines(state.ParentStyle()->AutoRepeatOrderedNamedGrid{{type}}Lines());
state.Style()->SetGridAutoRepeat{{type}}sType(state.ParentStyle()->GridAutoRepeat{{type}}sType());
{% endcall %}
{% call(property) apply_value(property) %}
GridTrackList track_sizes;
Vector<GridTrackSize> auto_repeat_track_sizes;
NamedGridLinesMap named_grid_lines;
OrderedNamedGridLines ordered_named_grid_lines;
NamedGridLinesMap auto_repeat_named_grid_lines;
OrderedNamedGridLines auto_repeat_ordered_named_grid_lines;
AutoRepeatType autoRepeatType = ComputedStyleInitialValues::InitialGridAutoRepeatType();
size_t auto_repeat_insertion_point =
ComputedStyleInitialValues::InitialGridAutoRepeatInsertionPoint();
StyleBuilderConverter::ConvertGridTrackList(
value, track_sizes, named_grid_lines, ordered_named_grid_lines,
auto_repeat_track_sizes, auto_repeat_named_grid_lines,
auto_repeat_ordered_named_grid_lines, auto_repeat_insertion_point,
autoRepeatType, state);
const NamedGridAreaMap& named_grid_areas = state.Style()->NamedGridArea();
if (!named_grid_areas.IsEmpty()) {
StyleBuilderConverter::CreateImplicitNamedGridLinesFromGridArea(
named_grid_areas, named_grid_lines, kFor{{type}}s);
}
state.Style()->SetGridTemplate{{type}}s(track_sizes);
state.Style()->SetNamedGrid{{type}}Lines(named_grid_lines);
state.Style()->SetOrderedNamedGrid{{type}}Lines(ordered_named_grid_lines);
state.Style()->SetGridAutoRepeat{{type}}s(auto_repeat_track_sizes);
state.Style()->SetGridAutoRepeat{{type}}sInsertionPoint(
auto_repeat_insertion_point);
state.Style()->SetAutoRepeatNamedGrid{{type}}Lines(auto_repeat_named_grid_lines);
state.Style()->SetAutoRepeatOrderedNamedGrid{{type}}Lines(
auto_repeat_ordered_named_grid_lines);
state.Style()->SetGridAutoRepeat{{type}}sType(autoRepeatType);
{% endcall %}
{% endif %}
{%- endmacro %}