Optimizing CSS vars

This commit is contained in:
Martín Lucas Golini
2020-04-21 03:59:23 -03:00
parent def943835e
commit b757f0c9ea
9 changed files with 120 additions and 88 deletions

View File

@@ -15,7 +15,7 @@ namespace EE { namespace UI { namespace CSS {
class EE_API AnimationDefinition {
public:
static std::unordered_map<std::string, AnimationDefinition>
parseAnimationProperties( const std::vector<StyleSheetProperty>& stylesheetProperties );
parseAnimationProperties( const std::vector<const StyleSheetProperty*>& stylesheetProperties );
/* https://developer.mozilla.org/en-US/docs/Web/CSS/animation-direction */
enum AnimationDirection {

View File

@@ -25,6 +25,11 @@ namespace EE { namespace UI { namespace CSS {
class PropertyDefinition;
class ShorthandDefinition;
struct VariableFunctionCache {
std::string definition;
std::vector<std::string> variableList;
};
class EE_API StyleSheetProperty {
public:
StyleSheetProperty();
@@ -167,6 +172,8 @@ class EE_API StyleSheetProperty {
const Uint32& getValueHash() const;
const std::vector<VariableFunctionCache>& getVarCache() const;
protected:
std::string mName;
Uint32 mNameHash;
@@ -180,6 +187,7 @@ class EE_API StyleSheetProperty {
const PropertyDefinition* mPropertyDefinition;
const ShorthandDefinition* mShorthandDefinition;
std::vector<StyleSheetProperty> mIndexedProperty;
std::vector<VariableFunctionCache> mVarCache;
explicit StyleSheetProperty( const bool& isVolatile, const PropertyDefinition* definition,
const std::string& value, const Uint32& specificity = 0,
@@ -188,6 +196,8 @@ class EE_API StyleSheetProperty {
void cleanValue();
void checkImportant();
void createIndexed();
void checkVars();
std::vector<VariableFunctionCache> checkVars( const std::string& value );
};
typedef std::map<Uint32, StyleSheetProperty> StyleSheetProperties;

View File

@@ -15,7 +15,7 @@ namespace EE { namespace UI { namespace CSS {
class EE_API TransitionDefinition {
public:
static std::map<std::string, TransitionDefinition>
parseTransitionProperties( const std::vector<StyleSheetProperty>& styleSheetProperties );
parseTransitionProperties( const std::vector<const StyleSheetProperty*>& styleSheetProperties );
TransitionDefinition() : timingFunction( Ease::Linear ) {}

View File

@@ -64,6 +64,7 @@ class EE_API UIStyle : public UIState {
void setDisableAnimations( bool disableAnimations );
const bool& isStructurallyVolatile() const;
protected:
UIWidget* mWidget;
CSS::StyleSheetStyleVector mCacheableStyles;
@@ -71,8 +72,8 @@ class EE_API UIStyle : public UIState {
CSS::StyleSheetStyle mElementStyle;
CSS::StyleSheetProperties mProperties;
CSS::StyleSheetVariables mVariables;
std::vector<CSS::StyleSheetProperty> mTransitionProperties;
std::vector<CSS::StyleSheetProperty> mAnimationProperties;
std::vector<const CSS::StyleSheetProperty*> mTransitionProperties;
std::vector<const CSS::StyleSheetProperty*> mAnimationProperties;
CSS::TransitionsMap mTransitions;
CSS::AnimationsMap mAnimations;
std::set<UIWidget*> mRelatedWidgets;
@@ -117,8 +118,6 @@ class EE_API UIStyle : public UIState {
void removeAnimation( const CSS::PropertyDefinition* propertyDefinition,
const Uint32& propertyIndex );
std::string varToVal( const std::string& varDef );
};
}} // namespace EE::UI

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.11.2, 2020-04-16T04:12:37. -->
<!-- Written by QtCreator 4.11.2, 2020-04-19T17:25:26. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
@@ -1531,7 +1531,7 @@
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">eepp-UIEditor-debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
<value type="QString" key="RunConfiguration.Arguments">-x assets/layouts/test.xml -c assets/layouts/test.css -u</value>
<value type="QString" key="RunConfiguration.Arguments">-x assets/layouts/test_widgets.xml -c assets/ui/breeze.css</value>
<value type="bool" key="RunConfiguration.Arguments.multi">false</value>
<value type="QString" key="RunConfiguration.OverrideDebuggerStartup"></value>
<value type="bool" key="RunConfiguration.UseCppDebugger">true</value>

View File

@@ -8,7 +8,7 @@ bool isTimingFunction( const std::string& str ) {
}
std::unordered_map<std::string, AnimationDefinition> AnimationDefinition::parseAnimationProperties(
const std::vector<StyleSheetProperty>& stylesheetProperties ) {
const std::vector<const StyleSheetProperty*>& stylesheetProperties ) {
AnimationsMap animations;
std::vector<std::string> names;
std::vector<Time> durations;
@@ -20,17 +20,17 @@ std::unordered_map<std::string, AnimationDefinition> AnimationDefinition::parseA
std::vector<bool> pausedStates;
for ( auto& prop : stylesheetProperties ) {
if ( prop.getPropertyDefinition() == NULL )
if ( prop->getPropertyDefinition() == NULL )
continue;
const PropertyDefinition* propDef = prop.getPropertyDefinition();
const PropertyDefinition* propDef = prop->getPropertyDefinition();
switch ( propDef->getPropertyId() ) {
case PropertyId::Animation: {
bool durationSet = false;
for ( size_t i = 0; i < prop.getPropertyIndexCount(); i++ ) {
const StyleSheetProperty& iProp = prop.getPropertyIndex( i );
for ( size_t i = 0; i < prop->getPropertyIndexCount(); i++ ) {
const StyleSheetProperty& iProp = prop->getPropertyIndex( i );
auto parts = String::split( iProp.getValue(), ' ' );
@@ -83,8 +83,8 @@ std::unordered_map<std::string, AnimationDefinition> AnimationDefinition::parseA
case PropertyId::AnimationPlayState:
case PropertyId::AnimationIterationCount:
case PropertyId::AnimationTimingFunction: {
for ( size_t i = 0; i < prop.getPropertyIndexCount(); i++ ) {
const StyleSheetProperty& iProp = prop.getPropertyIndex( i );
for ( size_t i = 0; i < prop->getPropertyIndexCount(); i++ ) {
const StyleSheetProperty& iProp = prop->getPropertyIndex( i );
std::string val( String::trim( String::toLower( iProp.getValue() ) ) );
switch ( propDef->getPropertyId() ) {
case PropertyId::AnimationName:

View File

@@ -26,12 +26,13 @@ StyleSheetProperty::StyleSheetProperty( const PropertyDefinition* definition,
mIndex( index ),
mVolatile( false ),
mImportant( false ),
mIsVarValue( String::contains( mValue, "var(" ) ),
mIsVarValue( false ),
mPropertyDefinition( definition ),
mShorthandDefinition( NULL ) {
cleanValue();
checkImportant();
createIndexed();
checkVars();
if ( NULL == mShorthandDefinition && NULL == mPropertyDefinition ) {
eePRINTL( "Property %s is not defined!", mName.c_str() );
@@ -48,13 +49,14 @@ StyleSheetProperty::StyleSheetProperty( const bool& isVolatile,
mValueHash( String::hash( mValue ) ),
mSpecificity( 0 ),
mIndex( index ),
mVolatile( false ),
mVolatile( isVolatile ),
mImportant( false ),
mIsVarValue( String::contains( mValue, "var(" ) ),
mIsVarValue( false ),
mPropertyDefinition( definition ),
mShorthandDefinition( NULL ) {
cleanValue();
checkImportant();
checkVars();
if ( NULL == mShorthandDefinition && NULL == mPropertyDefinition ) {
eePRINTL( "Property %s is not defined!", mName.c_str() );
@@ -71,7 +73,7 @@ StyleSheetProperty::StyleSheetProperty( const std::string& name, const std::stri
mIndex( 0 ),
mVolatile( false ),
mImportant( false ),
mIsVarValue( String::contains( mValue, "var(" ) ),
mIsVarValue( false ),
mPropertyDefinition( StyleSheetSpecification::instance()->getProperty( mNameHash ) ),
mShorthandDefinition( NULL == mPropertyDefinition
? StyleSheetSpecification::instance()->getShorthand( mNameHash )
@@ -79,6 +81,7 @@ StyleSheetProperty::StyleSheetProperty( const std::string& name, const std::stri
cleanValue();
checkImportant();
createIndexed();
checkVars();
if ( NULL == mShorthandDefinition && NULL == mPropertyDefinition ) {
eePRINTL( "Property %s is not defined!", mName.c_str() );
@@ -96,7 +99,7 @@ StyleSheetProperty::StyleSheetProperty( const std::string& name, const std::stri
mIndex( index ),
mVolatile( isVolatile ),
mImportant( false ),
mIsVarValue( String::contains( mValue, "var(" ) ),
mIsVarValue( false ),
mPropertyDefinition( StyleSheetSpecification::instance()->getProperty( mNameHash ) ),
mShorthandDefinition( NULL == mPropertyDefinition
? StyleSheetSpecification::instance()->getShorthand( mNameHash )
@@ -104,6 +107,7 @@ StyleSheetProperty::StyleSheetProperty( const std::string& name, const std::stri
cleanValue();
checkImportant();
createIndexed();
checkVars();
if ( NULL == mShorthandDefinition && NULL == mPropertyDefinition ) {
eePRINTL( "Property %s is not defined!" );
@@ -151,7 +155,7 @@ void StyleSheetProperty::setName( const std::string& name ) {
void StyleSheetProperty::setValue( const std::string& value ) {
mValue = value;
mValueHash = String::hash( value );
//mValueHash = String::hash( value );
mIsVarValue = String::startsWith( mValue, "var(" );
createIndexed();
}
@@ -191,13 +195,64 @@ void StyleSheetProperty::createIndexed() {
auto splitValues = String::split( getValue(), ",", "", "(\"" );
if ( !splitValues.empty() ) {
for ( size_t i = 0; i < splitValues.size(); i++ ) {
mIndexedProperty.emplace_back( StyleSheetProperty(
isVolatile(), getPropertyDefinition(), splitValues[i], getSpecificity(), i ) );
StyleSheetProperty index( mVolatile, mPropertyDefinition, splitValues[i],
mSpecificity, i );
mIndexedProperty.emplace_back( std::move( index ) );
}
}
}
}
void StyleSheetProperty::checkVars() {
auto varCache( checkVars( mValue ) );
mIsVarValue = false;
if ( !varCache.empty() ) {
mIsVarValue = true;
mVarCache = std::move( varCache );
}
}
static void varToVal( VariableFunctionCache& varCache, const std::string& varDef ) {
FunctionString functionType = FunctionString::parse( varDef );
if ( !functionType.getParameters().empty() ) {
for ( auto& val : functionType.getParameters() ) {
if ( String::startsWith( val, "--" ) ) {
varCache.variableList.emplace_back( val );
} else if ( String::startsWith( val, "var(" ) ) {
varToVal( varCache, val );
}
}
}
}
std::vector<VariableFunctionCache> StyleSheetProperty::checkVars( const std::string& value ) {
std::vector<VariableFunctionCache> vars;
std::string::size_type tokenStart = 0;
std::string::size_type tokenEnd = 0;
while ( true ) {
tokenStart = value.find( "var(", tokenStart );
if ( tokenStart != std::string::npos ) {
tokenEnd = String::findCloseBracket( value, tokenStart, '(', ')' );
if ( tokenEnd != std::string::npos ) {
mIsVarValue = true;
VariableFunctionCache variableFuncCache;
variableFuncCache.definition =
value.substr( tokenStart, tokenEnd + 1 - tokenStart );
varToVal( variableFuncCache, variableFuncCache.definition );
tokenStart = tokenEnd;
vars.emplace_back( std::move( variableFuncCache ) );
} else {
break;
}
} else {
break;
}
};
return vars;
}
std::string StyleSheetProperty::asString( const std::string& defaultValue ) const {
return mValue.empty() ? defaultValue : mValue;
}
@@ -602,4 +657,8 @@ const Uint32& StyleSheetProperty::getValueHash() const {
return mValueHash;
}
const std::vector<VariableFunctionCache>& StyleSheetProperty::getVarCache() const {
return mVarCache;
}
}}} // namespace EE::UI::CSS

View File

@@ -5,7 +5,7 @@
namespace EE { namespace UI { namespace CSS {
std::map<std::string, TransitionDefinition> TransitionDefinition::parseTransitionProperties(
const std::vector<StyleSheetProperty>& styleSheetProperties ) {
const std::vector<const StyleSheetProperty*>& styleSheetProperties ) {
std::vector<std::string> properties;
std::vector<Time> durations;
std::vector<Time> delays;
@@ -13,13 +13,13 @@ std::map<std::string, TransitionDefinition> TransitionDefinition::parseTransitio
TransitionsMap transitions;
for ( auto& prop : styleSheetProperties ) {
if ( prop.getPropertyDefinition() == NULL )
if ( prop->getPropertyDefinition() == NULL )
continue;
const PropertyDefinition* propDef = prop.getPropertyDefinition();
const PropertyDefinition* propDef = prop->getPropertyDefinition();
if ( propDef->getPropertyId() == PropertyId::Transition ) {
auto strTransitions = String::split( prop.getValue(), ',' );
auto strTransitions = String::split( prop->getValue(), ',' );
for ( auto tit = strTransitions.begin(); tit != strTransitions.end(); ++tit ) {
auto strTransition = String::trim( *tit );
@@ -32,7 +32,7 @@ std::map<std::string, TransitionDefinition> TransitionDefinition::parseTransitio
std::string property = String::trim( splitTransition[0] );
String::toLowerInPlace( property );
Time duration = StyleSheetProperty( prop.getName(),
Time duration = StyleSheetProperty( prop->getName(),
String::toLower( splitTransition[1] ) )
.asTime();
@@ -46,12 +46,12 @@ std::map<std::string, TransitionDefinition> TransitionDefinition::parseTransitio
if ( transitionDef.timingFunction == Ease::Linear &&
splitTransition[2] != "linear" && splitTransition.size() == 3 ) {
transitionDef.delay =
StyleSheetProperty( prop.getName(),
StyleSheetProperty( prop->getName(),
String::toLower( splitTransition[2] ) )
.asTime();
} else if ( splitTransition.size() >= 4 ) {
transitionDef.delay =
StyleSheetProperty( prop.getName(),
StyleSheetProperty( prop->getName(),
String::toLower( splitTransition[3] ) )
.asTime();
}
@@ -62,23 +62,23 @@ std::map<std::string, TransitionDefinition> TransitionDefinition::parseTransitio
}
}
} else if ( propDef->getPropertyId() == PropertyId::TransitionDuration ) {
auto strDurations = String::split( prop.getValue(), ',' );
auto strDurations = String::split( prop->getValue(), ',' );
for ( auto dit = strDurations.begin(); dit != strDurations.end(); ++dit ) {
std::string duration( String::trim( *dit ) );
String::toLowerInPlace( duration );
durations.push_back( StyleSheetProperty( prop.getName(), duration ).asTime() );
durations.push_back( StyleSheetProperty( prop->getName(), duration ).asTime() );
}
} else if ( propDef->getPropertyId() == PropertyId::TransitionDelay ) {
auto strDelays = String::split( prop.getValue(), ',' );
auto strDelays = String::split( prop->getValue(), ',' );
for ( auto dit = strDelays.begin(); dit != strDelays.end(); ++dit ) {
std::string delay( String::trim( *dit ) );
String::toLowerInPlace( delay );
delays.push_back( StyleSheetProperty( prop.getName(), delay ).asTime() );
delays.push_back( StyleSheetProperty( prop->getName(), delay ).asTime() );
}
} else if ( propDef->getPropertyId() == PropertyId::TransitionTimingFunction ) {
auto strTimingFuncs = String::split( prop.getValue(), ',' );
auto strTimingFuncs = String::split( prop->getValue(), ',' );
for ( auto dit = strTimingFuncs.begin(); dit != strTimingFuncs.end(); ++dit ) {
std::string timingFunction( String::trim( *dit ) );
@@ -86,7 +86,7 @@ std::map<std::string, TransitionDefinition> TransitionDefinition::parseTransitio
timingFunctions.push_back( Ease::fromName( timingFunction ) );
}
} else if ( propDef->getPropertyId() == PropertyId::TransitionProperty ) {
auto strProperties = String::split( prop.getValue(), ',' );
auto strProperties = String::split( prop->getValue(), ',' );
for ( auto dit = strProperties.begin(); dit != strProperties.end(); ++dit ) {
std::string property( String::trim( *dit ) );

View File

@@ -192,12 +192,10 @@ void UIStyle::tryApplyStyle( const StyleSheetStyle* style ) {
property.getSpecificity() >= it->second.getSpecificity() ) {
mProperties[property.getId()] = property;
applyVarValues( mProperties[property.getId()] );
if ( String::startsWith( property.getName(), "transition" ) )
mTransitionProperties.push_back( property );
mTransitionProperties.push_back( &property );
else if ( String::startsWith( property.getName(), "animation" ) )
mAnimationProperties.push_back( property );
mAnimationProperties.push_back( &property );
}
}
}
@@ -214,56 +212,18 @@ void UIStyle::findVariables( const StyleSheetStyle* style ) {
}
}
std::string UIStyle::varToVal( const std::string& varDef ) {
FunctionString functionType = FunctionString::parse( varDef );
if ( !functionType.getParameters().empty() ) {
for ( auto& val : functionType.getParameters() ) {
if ( String::startsWith( val, "--" ) ) {
StyleSheetVariable variable( getVariable( val ) );
if ( !variable.isEmpty() ) {
return variable.getValue();
}
} else if ( String::startsWith( val, "var(" ) ) {
return varToVal( val );
} else {
return val;
}
}
}
return "";
}
void UIStyle::setVariableFromValue( StyleSheetProperty& property, const std::string& value ) {
std::string::size_type tokenStart = 0;
std::string::size_type tokenEnd = 0;
std::string newValue( value );
while ( true ) {
tokenStart = newValue.find( "var(", tokenStart );
if ( tokenStart != std::string::npos ) {
tokenEnd = String::findCloseBracket( value, tokenStart, '(', ')' );
if ( tokenEnd != std::string::npos ) {
std::string varDef( newValue.substr( tokenStart, tokenEnd + 1 - tokenStart ) );
String::replaceAll( newValue, varDef, varToVal( varDef ) );
} else {
for ( auto& var : property.getVarCache() ) {
for ( auto& val : var.variableList ) {
StyleSheetVariable variable( getVariable( val ) );
if ( !variable.isEmpty() ) {
String::replaceAll( newValue, var.definition, variable.getValue() );
break;
}
} else {
break;
}
};
property.setValue( newValue );
if ( newValue.empty() ) {
eePRINTL( "Invalid var: \"%s\" for property: %s", value.c_str(),
property.getName().c_str() );
}
property.setValue( newValue );
}
void UIStyle::applyVarValues( StyleSheetProperty& property ) {
@@ -305,6 +265,10 @@ void UIStyle::onStateChange() {
}
if ( !mapEquals( mProperties, prevProperties ) || mForceReapplyProperties ) {
for ( auto& prop : mProperties ) {
applyVarValues( prop.second );
}
mForceReapplyProperties = false;
mWidget->beginAttributesTransaction();
@@ -580,13 +544,13 @@ void UIStyle::updateAnimationsPlayState() {
// "animation-play-state" definition.
bool isSet = false;
for ( auto& animProp : mAnimationProperties ) {
if ( NULL != animProp.getPropertyDefinition() &&
animProp.getPropertyDefinition()->getPropertyId() ==
if ( NULL != animProp->getPropertyDefinition() &&
animProp->getPropertyDefinition()->getPropertyId() ==
PropertyId::AnimationPlayState ) {
// If found, get the pause/running state of the property, using the
// index of the current animation, and set the animation.play-state.
size_t animPropCount = animProp.getPropertyIndexCount();
bool paused = animProp.getPropertyIndex( animPos % animPropCount )
size_t animPropCount = animProp->getPropertyIndexCount();
bool paused = animProp->getPropertyIndex( animPos % animPropCount )
.getValue() == "paused"
? true
: false;