mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
This is for doing masking based off the alpha channel of an image. This is a feature we want to support, but we want a more general imperative API that the declarative thing is built on top of. In the meantime, the code is getting in our way and the feature was already broken (likely from before making sky public). We just paint the mask image on top instead of doing the actual masking. This patch just removes the parsing. Followup patches will remove the implementation code. R=esprehn@chromium.org Review URL: https://codereview.chromium.org/892903002
468 lines
18 KiB
Cheetah
468 lines
18 KiB
Cheetah
{% from 'macros.tmpl' import license %}
|
|
{#
|
|
This file is for property handlers which use the templating engine to
|
|
reduce (handwritten) code duplication.
|
|
|
|
The `properties' dict can be used to access a property's parameters in
|
|
jinja2 templates (i.e. setter, getter, initial, type_name)
|
|
#}
|
|
#include "config.h"
|
|
#include "StyleBuilderFunctions.h"
|
|
|
|
#include "CSSValueKeywords.h"
|
|
#include "core/css/BasicShapeFunctions.h"
|
|
#include "core/css/CSSPrimitiveValueMappings.h"
|
|
#include "core/css/Pair.h"
|
|
#include "core/css/resolver/StyleResolverState.h"
|
|
|
|
{% macro declare_initial_function(property_id) %}
|
|
void StyleBuilderFunctions::applyInitial{{property_id}}(StyleResolverState& state)
|
|
{%- endmacro %}
|
|
{% macro declare_inherit_function(property_id) %}
|
|
void StyleBuilderFunctions::applyInherit{{property_id}}(StyleResolverState& state)
|
|
{%- endmacro %}
|
|
{% macro declare_value_function(property_id) %}
|
|
void StyleBuilderFunctions::applyValue{{property_id}}(StyleResolverState& state, CSSValue* value)
|
|
{%- endmacro %}
|
|
{% macro set_value(property) %}
|
|
{%- if property.font %}
|
|
state.fontBuilder().{{property.setter}}
|
|
{%- else %}
|
|
state.style()->{{property.setter}}
|
|
{%- endif %}
|
|
{% endmacro %}
|
|
{% macro convert_and_set_value(property) %}
|
|
{% if property.converter %}
|
|
{{set_value(property)}}(StyleBuilderConverter::{{property.converter}}(state, value));
|
|
{%- else %}
|
|
{{set_value(property)}}(static_cast<{{property.type_name}}>(*toCSSPrimitiveValue(value)));
|
|
{%- endif %}
|
|
{% endmacro %}
|
|
|
|
namespace blink {
|
|
|
|
{% for property_id, property in properties.items() if property.should_declare_functions %}
|
|
{% set apply_type = property.apply_type %}
|
|
{% if not property.custom_initial %}
|
|
{{declare_initial_function(property_id)}}
|
|
{
|
|
{% if property.font %}
|
|
{{set_value(property)}}(FontBuilder::{{property.initial}}());
|
|
{% else %}
|
|
{{set_value(property)}}(RenderStyle::{{property.initial}}());
|
|
{% endif %}
|
|
}
|
|
|
|
{% endif %}
|
|
{% if not property.custom_inherit %}
|
|
{{declare_inherit_function(property_id)}}
|
|
{
|
|
{% if property.font %}
|
|
{{set_value(property)}}(state.parentFontDescription().{{property.getter}}());
|
|
{% else %}
|
|
{{set_value(property)}}(state.parentStyle()->{{property.getter}}());
|
|
{% endif %}
|
|
}
|
|
|
|
{% endif %}
|
|
{% if not property.custom_value %}
|
|
{{declare_value_function(property_id)}}
|
|
{
|
|
{{convert_and_set_value(property)}}
|
|
}
|
|
|
|
{% endif %}
|
|
{% endfor %}
|
|
|
|
{% macro apply_animation(property_id, attribute, animation) %}
|
|
{% set vector = attribute|lower_first + "List()" %}
|
|
{{declare_initial_function(property_id)}}
|
|
{
|
|
CSS{{animation}}Data& data = state.style()->access{{animation}}s();
|
|
data.{{vector}}.clear();
|
|
data.{{vector}}.append(CSS{{animation}}Data::initial{{attribute}}());
|
|
}
|
|
|
|
{{declare_inherit_function(property_id)}}
|
|
{
|
|
const CSS{{animation}}Data* parentData = state.parentStyle()->{{animation|lower}}s();
|
|
if (!parentData)
|
|
applyInitial{{property_id}}(state);
|
|
else
|
|
state.style()->access{{animation}}s().{{vector}} = parentData->{{vector}};
|
|
}
|
|
|
|
{{declare_value_function(property_id)}}
|
|
{
|
|
CSS{{animation}}Data& data = state.style()->access{{animation}}s();
|
|
data.{{vector}}.clear();
|
|
for (CSSValueListIterator i = value; i.hasMore(); i.advance())
|
|
data.{{vector}}.append(state.styleMap().mapAnimation{{attribute}}(i.value()));
|
|
}
|
|
{% endmacro %}
|
|
{{apply_animation('CSSPropertyAnimationDelay', 'Delay', 'Animation')}}
|
|
{{apply_animation('CSSPropertyAnimationDirection', 'Direction', 'Animation')}}
|
|
{{apply_animation('CSSPropertyAnimationDuration', 'Duration', 'Animation')}}
|
|
{{apply_animation('CSSPropertyAnimationFillMode', 'FillMode', 'Animation')}}
|
|
{{apply_animation('CSSPropertyAnimationIterationCount', 'IterationCount', 'Animation')}}
|
|
{{apply_animation('CSSPropertyAnimationName', 'Name', 'Animation')}}
|
|
{{apply_animation('CSSPropertyAnimationPlayState', 'PlayState', 'Animation')}}
|
|
{{apply_animation('CSSPropertyAnimationTimingFunction', 'TimingFunction', 'Animation')}}
|
|
{{apply_animation('CSSPropertyTransitionDelay', 'Delay', 'Transition')}}
|
|
{{apply_animation('CSSPropertyTransitionDuration', 'Duration', 'Transition')}}
|
|
{{apply_animation('CSSPropertyTransitionProperty', 'Property', 'Transition')}}
|
|
{{apply_animation('CSSPropertyTransitionTimingFunction', 'TimingFunction', 'Transition')}}
|
|
|
|
{% macro apply_auto(property_id, auto_getter=none, auto_setter=none, auto_identity='CSSValueAuto') %}
|
|
{% set property = properties[property_id] %}
|
|
{% set auto_getter = auto_getter or 'hasAuto' + property.name_for_methods %}
|
|
{% set auto_setter = auto_setter or 'setHasAuto' + property.name_for_methods %}
|
|
{{declare_initial_function(property_id)}}
|
|
{
|
|
state.style()->{{auto_setter}}();
|
|
}
|
|
|
|
{{declare_inherit_function(property_id)}}
|
|
{
|
|
if (state.parentStyle()->{{auto_getter}}())
|
|
state.style()->{{auto_setter}}();
|
|
else
|
|
{{set_value(property)}}(state.parentStyle()->{{property.getter}}());
|
|
}
|
|
|
|
{{declare_value_function(property_id)}}
|
|
{
|
|
if (!value->isPrimitiveValue())
|
|
return;
|
|
|
|
CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
|
|
if (primitiveValue->getValueID() == {{auto_identity}})
|
|
state.style()->{{auto_setter}}();
|
|
else
|
|
{{convert_and_set_value(property)}}
|
|
}
|
|
{% endmacro %}
|
|
{{apply_auto('CSSPropertyClip')}}
|
|
{{apply_auto('CSSPropertyOrphans')}}
|
|
{{apply_auto('CSSPropertyWidows')}}
|
|
{{apply_auto('CSSPropertyZIndex')}}
|
|
|
|
static bool lengthTypeAndValueMatch(const Length& length, LengthType type, float value)
|
|
{
|
|
return length.type() == type && length.value() == value;
|
|
}
|
|
|
|
static bool lengthTypeAndValueMatch(const LengthBox& lengthBox, LengthType type, float value)
|
|
{
|
|
return (lengthTypeAndValueMatch(lengthBox.left(), type, value)
|
|
&& lengthTypeAndValueMatch(lengthBox.right(), type, value)
|
|
&& lengthTypeAndValueMatch(lengthBox.top(), type, value)
|
|
&& lengthTypeAndValueMatch(lengthBox.bottom(), type, value));
|
|
}
|
|
|
|
static bool lengthTypeAndValueMatch(const BorderImageLength& borderImageLength, LengthType type, float value)
|
|
{
|
|
return borderImageLength.isLength() && lengthTypeAndValueMatch(borderImageLength.length(), type, value);
|
|
}
|
|
|
|
static bool lengthTypeAndValueMatch(const BorderImageLengthBox& borderImageLengthBox, LengthType type, float value)
|
|
{
|
|
return (lengthTypeAndValueMatch(borderImageLengthBox.left(), type, value)
|
|
&& lengthTypeAndValueMatch(borderImageLengthBox.right(), type, value)
|
|
&& lengthTypeAndValueMatch(borderImageLengthBox.top(), type, value)
|
|
&& lengthTypeAndValueMatch(borderImageLengthBox.bottom(), type, value));
|
|
}
|
|
|
|
{% macro apply_border_image_modifier(property_id, modifier_type) %}
|
|
{% set is_mask_box = 'MaskBox' in property_id %}
|
|
{% set getter = 'maskBoxImage' if is_mask_box else 'borderImage' %}
|
|
{% set setter = 'setMaskBoxImage' if is_mask_box else 'setBorderImage' %}
|
|
{{ declare_initial_function(property_id) }}
|
|
{
|
|
const NinePieceImage& currentImage = state.style()->{{getter}}();
|
|
{# Check for equality in case we can bail out before creating a new NinePieceImage. #}
|
|
{% if modifier_type == 'Outset' %}
|
|
if (lengthTypeAndValueMatch(currentImage.outset(), Fixed, 0))
|
|
return;
|
|
{% elif modifier_type == 'Repeat' %}
|
|
if (currentImage.horizontalRule() == StretchImageRule && currentImage.verticalRule() == StretchImageRule)
|
|
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 (currentImage.fill() == true && lengthTypeAndValueMatch(currentImage.imageSlices(), Fixed, 0))
|
|
return;
|
|
{% elif modifier_type == 'Slice' and not is_mask_box %}
|
|
if (currentImage.fill() == false && lengthTypeAndValueMatch(currentImage.imageSlices(), 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 (lengthTypeAndValueMatch(currentImage.borderSlices(), Auto, 0))
|
|
return;
|
|
{% elif modifier_type == 'Width' and not is_mask_box %}
|
|
if (lengthTypeAndValueMatch(currentImage.borderSlices(), Fixed, 1))
|
|
return;
|
|
{% endif %}
|
|
|
|
NinePieceImage image(currentImage);
|
|
{% if modifier_type == 'Outset' %}
|
|
image.setOutset(Length(0, Fixed));
|
|
{% elif modifier_type == 'Repeat' %}
|
|
image.setHorizontalRule(StretchImageRule);
|
|
image.setVerticalRule(StretchImageRule);
|
|
{% elif modifier_type == 'Slice' and is_mask_box %}
|
|
image.setImageSlices(LengthBox({{ (['Length(0, Fixed)']*4) | join(', ') }}));
|
|
image.setFill(true);
|
|
{% elif modifier_type == 'Slice' and not is_mask_box %}
|
|
image.setImageSlices(LengthBox({{ (['Length(100, Percent)']*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);
|
|
}
|
|
|
|
{{declare_inherit_function(property_id)}}
|
|
{
|
|
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);
|
|
}
|
|
|
|
{{declare_value_function(property_id)}}
|
|
{
|
|
NinePieceImage image(state.style()->{{getter}}());
|
|
{% if modifier_type == 'Outset' %}
|
|
image.setOutset(state.styleMap().mapNinePieceImageQuad(value));
|
|
{% elif modifier_type == 'Repeat' %}
|
|
state.styleMap().mapNinePieceImageRepeat(value, image);
|
|
{% elif modifier_type == 'Slice' %}
|
|
state.styleMap().mapNinePieceImageSlice(value, image);
|
|
{% elif modifier_type == 'Width' %}
|
|
image.setBorderSlices(state.styleMap().mapNinePieceImageQuad(value));
|
|
{% endif %}
|
|
state.style()->{{setter}}(image);
|
|
}
|
|
{% endmacro %}
|
|
{{apply_border_image_modifier('CSSPropertyBorderImageOutset', 'Outset')}}
|
|
{{apply_border_image_modifier('CSSPropertyBorderImageRepeat', 'Repeat')}}
|
|
{{apply_border_image_modifier('CSSPropertyBorderImageSlice', 'Slice')}}
|
|
{{apply_border_image_modifier('CSSPropertyBorderImageWidth', 'Width')}}
|
|
|
|
{% macro apply_value_border_image_source(property_id) %}
|
|
{{declare_value_function(property_id)}}
|
|
{
|
|
{% set property = properties[property_id] %}
|
|
{{set_value(property)}}(state.styleImage({{property_id}}, value));
|
|
}
|
|
{% endmacro %}
|
|
{{apply_value_border_image_source('CSSPropertyBorderImageSource')}}
|
|
|
|
{% macro apply_color(property_id, initial_color='StyleColor::currentColor') %}
|
|
{% set property = properties[property_id] %}
|
|
{{declare_initial_function(property_id)}}
|
|
{
|
|
StyleColor color = {{initial_color}}();
|
|
{{set_value(property)}}(color);
|
|
}
|
|
|
|
{{declare_inherit_function(property_id)}}
|
|
{
|
|
StyleColor color = state.parentStyle()->{{property.getter}}();
|
|
Color resolvedColor = color.resolve(state.parentStyle()->color());
|
|
{{set_value(property)}}(resolvedColor);
|
|
}
|
|
|
|
{{declare_value_function(property_id)}}
|
|
{
|
|
{{set_value(property)}}(StyleBuilderConverter::convertColor(state, value));
|
|
}
|
|
{% endmacro %}
|
|
{{apply_color('CSSPropertyBackgroundColor', initial_color='RenderStyle::initialBackgroundColor') }}
|
|
{{apply_color('CSSPropertyBorderBottomColor')}}
|
|
{{apply_color('CSSPropertyBorderLeftColor')}}
|
|
{{apply_color('CSSPropertyBorderRightColor')}}
|
|
{{apply_color('CSSPropertyBorderTopColor')}}
|
|
{{apply_color('CSSPropertyOutlineColor')}}
|
|
{{apply_color('CSSPropertyTextDecorationColor')}}
|
|
{{apply_color('CSSPropertyWebkitTextEmphasisColor')}}
|
|
{{apply_color('CSSPropertyWebkitTextFillColor')}}
|
|
{{apply_color('CSSPropertyWebkitTextStrokeColor')}}
|
|
|
|
{% macro apply_counter(property_id, action) %}
|
|
{% set property = properties[property_id] %}
|
|
{{declare_initial_function(property_id)}} { }
|
|
|
|
{{declare_inherit_function(property_id)}}
|
|
{
|
|
CounterDirectiveMap& map = state.style()->accessCounterDirectives();
|
|
CounterDirectiveMap& parentMap = state.parentStyle()->accessCounterDirectives();
|
|
|
|
typedef CounterDirectiveMap::iterator Iterator;
|
|
Iterator end = parentMap.end();
|
|
for (Iterator it = parentMap.begin(); it != end; ++it) {
|
|
CounterDirectives& directives = map.add(it->key, CounterDirectives()).storedValue->value;
|
|
directives.inherit{{action}}(it->value);
|
|
}
|
|
}
|
|
|
|
{{declare_value_function(property_id)}}
|
|
{
|
|
CounterDirectiveMap& map = state.style()->accessCounterDirectives();
|
|
typedef CounterDirectiveMap::iterator Iterator;
|
|
|
|
Iterator end = map.end();
|
|
for (Iterator it = map.begin(); it != end; ++it)
|
|
it->value.clear{{action}}();
|
|
|
|
if (!value->isValueList()) {
|
|
ASSERT(value->isPrimitiveValue() && toCSSPrimitiveValue(value)->getValueID() == CSSValueNone);
|
|
return;
|
|
}
|
|
|
|
CSSValueList* list = toCSSValueList(value);
|
|
|
|
int length = list ? list->length() : 0;
|
|
for (int i = 0; i < length; ++i) {
|
|
CSSValue* currValue = list->item(i);
|
|
if (!currValue->isPrimitiveValue())
|
|
continue;
|
|
|
|
Pair* pair = toCSSPrimitiveValue(currValue)->getPairValue();
|
|
if (!pair || !pair->first() || !pair->second())
|
|
continue;
|
|
|
|
AtomicString identifier(pair->first()->getStringValue());
|
|
int value = pair->second()->getIntValue();
|
|
CounterDirectives& directives = map.add(identifier, CounterDirectives()).storedValue->value;
|
|
{% if action == 'Reset' %}
|
|
directives.setResetValue(value);
|
|
{% else %}
|
|
directives.addIncrementValue(value);
|
|
{% endif %}
|
|
}
|
|
}
|
|
{% endmacro %}
|
|
|
|
{% macro apply_fill_layer(property_id, fill_type) %}
|
|
{% set layer_type = 'Background' if 'Background' in property_id else 'Mask' %}
|
|
{% set fill_layer_type = layer_type + 'FillLayer' %}
|
|
{% set access_layers = 'access' + layer_type + 'Layers' %}
|
|
{% set map_fill = 'mapFill' + fill_type %}
|
|
{{declare_initial_function(property_id)}}
|
|
{
|
|
FillLayer* currChild = &state.style()->{{access_layers}}();
|
|
currChild->set{{fill_type}}(FillLayer::initialFill{{fill_type}}({{fill_layer_type}}));
|
|
for (currChild = currChild->next(); currChild; currChild = currChild->next())
|
|
currChild->clear{{fill_type}}();
|
|
}
|
|
|
|
{{declare_inherit_function(property_id)}}
|
|
{
|
|
FillLayer* currChild = &state.style()->{{access_layers}}();
|
|
FillLayer* prevChild = 0;
|
|
const FillLayer* currParent = &state.parentStyle()->{{layer_type|lower}}Layers();
|
|
while (currParent && currParent->is{{fill_type}}Set()) {
|
|
if (!currChild)
|
|
currChild = prevChild->ensureNext();
|
|
currChild->set{{fill_type}}(currParent->{{fill_type|lower_first}}());
|
|
prevChild = currChild;
|
|
currChild = prevChild->next();
|
|
currParent = currParent->next();
|
|
}
|
|
|
|
while (currChild) {
|
|
/* Reset any remaining layers to not have the property set. */
|
|
currChild->clear{{fill_type}}();
|
|
currChild = currChild->next();
|
|
}
|
|
}
|
|
|
|
{{declare_value_function(property_id)}}
|
|
{
|
|
FillLayer* currChild = &state.style()->{{access_layers}}();
|
|
FillLayer* prevChild = 0;
|
|
if (value->isValueList() && !value->isImageSetValue()) {
|
|
/* Walk each value and put it into a layer, creating new layers as needed. */
|
|
CSSValueList* valueList = toCSSValueList(value);
|
|
for (unsigned int i = 0; i < valueList->length(); i++) {
|
|
if (!currChild)
|
|
currChild = prevChild->ensureNext();
|
|
state.styleMap().{{map_fill}}(currChild, valueList->item(i));
|
|
prevChild = currChild;
|
|
currChild = currChild->next();
|
|
}
|
|
} else {
|
|
state.styleMap().{{map_fill}}(currChild, value);
|
|
currChild = currChild->next();
|
|
}
|
|
while (currChild) {
|
|
/* Reset all remaining layers to not have the property set. */
|
|
currChild->clear{{fill_type}}();
|
|
currChild = currChild->next();
|
|
}
|
|
}
|
|
{% endmacro %}
|
|
{{apply_fill_layer('CSSPropertyBackgroundAttachment', 'Attachment')}}
|
|
{{apply_fill_layer('CSSPropertyBackgroundClip', 'Clip')}}
|
|
{{apply_fill_layer('CSSPropertyBackgroundImage', 'Image')}}
|
|
{{apply_fill_layer('CSSPropertyBackgroundOrigin', 'Origin')}}
|
|
{{apply_fill_layer('CSSPropertyBackgroundPositionX', 'XPosition')}}
|
|
{{apply_fill_layer('CSSPropertyBackgroundPositionY', 'YPosition')}}
|
|
{{apply_fill_layer('CSSPropertyBackgroundRepeatX', 'RepeatX')}}
|
|
{{apply_fill_layer('CSSPropertyBackgroundRepeatY', 'RepeatY')}}
|
|
{{apply_fill_layer('CSSPropertyBackgroundSize', 'Size')}}
|
|
{{apply_fill_layer('CSSPropertyWebkitBackgroundComposite', 'Composite')}}
|
|
|
|
{% macro apply_value_number(property_id, id_for_minus_one) %}
|
|
{{declare_value_function(property_id)}}
|
|
{
|
|
{% set property = properties[property_id] %}
|
|
if (!value->isPrimitiveValue())
|
|
return;
|
|
|
|
CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
|
|
if (primitiveValue->getValueID() == {{id_for_minus_one}})
|
|
{{set_value(property)}}(-1);
|
|
else
|
|
{{set_value(property)}}(primitiveValue->getValue<{{property.type_name}}>(CSSPrimitiveValue::CSS_NUMBER));
|
|
}
|
|
{% endmacro %}
|
|
|
|
{% macro apply_alignment(property_id, alignment_type) %}
|
|
{% set property = properties[property_id] %}
|
|
{{declare_initial_function(property_id)}}
|
|
{
|
|
state.style()->set{{alignment_type}}(RenderStyle::initial{{alignment_type}}());
|
|
state.style()->set{{alignment_type}}OverflowAlignment(RenderStyle::initial{{alignment_type}}OverflowAlignment());
|
|
}
|
|
|
|
{{declare_inherit_function(property_id)}}
|
|
{
|
|
state.style()->set{{alignment_type}}(state.parentStyle()->{{property.getter}}());
|
|
state.style()->set{{alignment_type}}OverflowAlignment(state.parentStyle()->{{property.getter}}OverflowAlignment());
|
|
}
|
|
|
|
{{declare_value_function(property_id)}}
|
|
{
|
|
CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
|
|
if (Pair* pairValue = primitiveValue->getPairValue()) {
|
|
state.style()->set{{alignment_type}}(*pairValue->first());
|
|
state.style()->set{{alignment_type}}OverflowAlignment(*pairValue->second());
|
|
} else {
|
|
state.style()->set{{alignment_type}}(*primitiveValue);
|
|
}
|
|
}
|
|
{% endmacro %}
|
|
{{apply_alignment('CSSPropertyAlignItems', 'AlignItems')}}
|
|
{{apply_alignment('CSSPropertyAlignSelf', 'AlignSelf')}}
|
|
|
|
} // namespace blink
|