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