diff --git a/bin/unit_tests/assets/html/eepp-ui-anchor-margins.webp b/bin/unit_tests/assets/html/eepp-ui-anchor-margins.webp index 70f198101..e8e35dabb 100644 Binary files a/bin/unit_tests/assets/html/eepp-ui-anchor-margins.webp and b/bin/unit_tests/assets/html/eepp-ui-anchor-margins.webp differ diff --git a/bin/unit_tests/assets/html/eepp-ui-span-padding.webp b/bin/unit_tests/assets/html/eepp-ui-span-padding.webp index 6ddf9b8fb..63545e563 100644 Binary files a/bin/unit_tests/assets/html/eepp-ui-span-padding.webp and b/bin/unit_tests/assets/html/eepp-ui-span-padding.webp differ diff --git a/include/eepp/ui/css/shorthanddefinition.hpp b/include/eepp/ui/css/shorthanddefinition.hpp index 4a283d587..e97de7db7 100644 --- a/include/eepp/ui/css/shorthanddefinition.hpp +++ b/include/eepp/ui/css/shorthanddefinition.hpp @@ -24,7 +24,8 @@ enum class ShorthandId : Uint32 { BorderWidth = String::hash( "border-width" ), BorderRadius = String::hash( "border-radius" ), MinSize = String::hash( "min-size" ), - MaxSize = String::hash( "max-size" ) + MaxSize = String::hash( "max-size" ), + Font = String::hash( "font" ) }; typedef std::function( const ShorthandDefinition* shorthand, diff --git a/src/eepp/ui/css/shorthanddefinition.cpp b/src/eepp/ui/css/shorthanddefinition.cpp index 3331756db..49d507a0c 100644 --- a/src/eepp/ui/css/shorthanddefinition.cpp +++ b/src/eepp/ui/css/shorthanddefinition.cpp @@ -21,7 +21,7 @@ ShorthandDefinition::ShorthandDefinition( const std::string& name, mFuncName( shorthandParserName ), mId( String::hash( name ) ), mProperties( properties ) { - for ( auto& sep : {"-", "_"} ) { + for ( auto& sep : { "-", "_" } ) { if ( mName.find( sep ) != std::string::npos ) { std::string alias( name ); String::replaceAll( alias, sep, "" ); diff --git a/src/eepp/ui/css/stylesheetspecification.cpp b/src/eepp/ui/css/stylesheetspecification.cpp index 5aec8e9ba..5cf4ee98d 100644 --- a/src/eepp/ui/css/stylesheetspecification.cpp +++ b/src/eepp/ui/css/stylesheetspecification.cpp @@ -522,6 +522,8 @@ void StyleSheetSpecification::registerDefaultProperties() { registerShorthand( "list-style", { "list-style-type", "list-style-position", "list-style-image" }, "list-style" ); + registerShorthand( "font", { "font-style", "font-size", "line-spacing", "font-family" }, + "font" ); } void StyleSheetSpecification::registerNodeSelector( const std::string& name, @@ -1175,6 +1177,152 @@ void StyleSheetSpecification::registerDefaultShorthandParsers() { } return properties; }; + + mShorthandParsers["font"] = []( const ShorthandDefinition* shorthand, + std::string value ) -> std::vector { + value = String::trim( value ); + if ( value.empty() ) + return {}; + + std::string lowerVal = String::toLower( value ); + static const std::string systemFonts[] = { "caption", "icon", "menu", + "message-box", "small-caption", "status-bar" }; + for ( const auto& sysFont : systemFonts ) { + if ( lowerVal == sysFont ) + return {}; + } + + std::vector properties; + const std::vector& propNames = shorthand->getProperties(); + + int stylePos = getIndexEndingWith( propNames, "-style" ); + int sizePos = getIndexEndingWith( propNames, "-size" ); + int linePos = getIndexEndingWith( propNames, "-spacing" ); + int familyPos = getIndexEndingWith( propNames, "-family" ); + + static const std::string sizeKeywords[] = { + "xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large", "xxx-large" }; + + auto isSizeKeyword = []( const std::string& t ) { + std::string lt = String::toLower( t ); + for ( const auto& kw : sizeKeywords ) { + if ( lt == kw ) + return true; + } + return false; + }; + + auto isStyleWord = []( const std::string& t ) { + std::string lt = String::toLower( t ); + return lt == "italic" || lt == "oblique" || lt == "normal"; + }; + + auto isWeightWord = []( const std::string& t ) { + std::string lt = String::toLower( t ); + return lt == "bold" || lt == "bolder" || lt == "lighter" || lt == "100" || + lt == "200" || lt == "300" || lt == "400" || lt == "500" || lt == "600" || + lt == "700" || lt == "800" || lt == "900"; + }; + + auto isNumberOrLength = []( const std::string& t ) { + if ( t.empty() ) + return false; + return ( t[0] >= '0' && t[0] <= '9' ) || t[0] == '.' || t[0] == '-'; + }; + + std::vector tokens = String::split( value, " ", "", "(", "\"" ); + std::string styleStr; + std::string sizeStr; + std::string lineStr; + std::string familyStr; + bool inLineHeight = false; + + for ( size_t i = 0; i < tokens.size(); i++ ) { + std::string tok = tokens[i]; + String::trimInPlace( tok ); + if ( tok.empty() ) + continue; + + if ( tok == "/" ) { + inLineHeight = true; + continue; + } + + if ( !inLineHeight ) { + size_t slashPos = tok.find( '/' ); + if ( slashPos != std::string::npos ) { + if ( slashPos == 0 ) { + lineStr = tok.substr( 1 ); + String::trimInPlace( lineStr ); + continue; + } + sizeStr = tok.substr( 0, slashPos ); + lineStr = tok.substr( slashPos + 1 ); + String::trimInPlace( lineStr ); + continue; + } + } + + if ( inLineHeight ) { + lineStr += ( lineStr.empty() ? "" : " " ) + tok; + inLineHeight = false; + continue; + } + + if ( !sizeStr.empty() && familyStr.empty() && !isStyleWord( tok ) && + !isWeightWord( tok ) ) { + familyStr += ( familyStr.empty() ? "" : " " ) + tok; + continue; + } + + if ( isStyleWord( tok ) ) { + std::string lt = String::toLower( tok ); + if ( lt != "normal" ) { + if ( !styleStr.empty() ) + styleStr += "|"; + styleStr += lt; + } + continue; + } + + if ( isWeightWord( tok ) ) { + std::string lt = String::toLower( tok ); + if ( lt != "normal" ) { + if ( !styleStr.empty() ) + styleStr += "|"; + styleStr += "bold"; + } + continue; + } + + if ( sizeStr.empty() && ( isNumberOrLength( tok ) || isSizeKeyword( tok ) ) ) { + sizeStr = tok; + continue; + } + + familyStr += ( familyStr.empty() ? "" : " " ) + tok; + } + + if ( !sizeStr.empty() ) { + if ( stylePos != -1 && !styleStr.empty() ) + properties.emplace_back( StyleSheetProperty( propNames[stylePos], styleStr ) ); + if ( sizePos != -1 ) + properties.emplace_back( StyleSheetProperty( propNames[sizePos], sizeStr ) ); + if ( linePos != -1 && !lineStr.empty() ) + properties.emplace_back( StyleSheetProperty( propNames[linePos], lineStr ) ); + if ( familyPos != -1 && !familyStr.empty() ) { + String::trimInPlace( familyStr ); + if ( familyStr.size() >= 2 && + ( ( familyStr[0] == '"' && familyStr.back() == '"' ) || + ( familyStr[0] == '\'' && familyStr.back() == '\'' ) ) ) { + familyStr = familyStr.substr( 1, familyStr.size() - 2 ); + } + properties.emplace_back( StyleSheetProperty( propNames[familyPos], familyStr ) ); + } + } + + return properties; + }; } }}} // namespace EE::UI::CSS