diff --git a/src/eepp/graphics/csslayouttypes.cpp b/src/eepp/graphics/csslayouttypes.cpp
index 52d0bd327..e068b1c28 100644
--- a/src/eepp/graphics/csslayouttypes.cpp
+++ b/src/eepp/graphics/csslayouttypes.cpp
@@ -40,6 +40,16 @@ std::string CSSDisplayHelper::toString( CSSDisplay display ) {
};
CSSDisplay CSSDisplayHelper::fromString( std::string_view val ) {
+ static constexpr std::string_view VendorPrefixes[] = { "-webkit-", "-moz-", "-ms-", "-o-" };
+ if ( !val.empty() && val.front() == '-' ) {
+ for ( std::string_view prefix : VendorPrefixes ) {
+ if ( val.size() > prefix.size() && val.substr( 0, prefix.size() ) == prefix ) {
+ val.remove_prefix( prefix.size() );
+ break;
+ }
+ }
+ }
+
CSSDisplay display = CSSDisplay::Block;
if ( val == "inline" )
display = CSSDisplay::Inline;
diff --git a/src/tests/unit_tests/uihtml_flex_test.cpp b/src/tests/unit_tests/uihtml_flex_test.cpp
index d59ca740a..be96f7b84 100644
--- a/src/tests/unit_tests/uihtml_flex_test.cpp
+++ b/src/tests/unit_tests/uihtml_flex_test.cpp
@@ -35,6 +35,63 @@ static void init_flex_test() {
themeManager->applyDefaultTheme( sceneNode->getRoot() );
}
+UTEST( FlexContainer, vendorPrefixedDisplayValues ) {
+ EXPECT_EQ( CSSDisplayHelper::fromString( "-webkit-flex" ), CSSDisplay::Flex );
+ EXPECT_EQ( CSSDisplayHelper::fromString( "-webkit-inline-flex" ), CSSDisplay::InlineFlex );
+ EXPECT_EQ( CSSDisplayHelper::fromString( "-moz-flex" ), CSSDisplay::Flex );
+ EXPECT_EQ( CSSDisplayHelper::fromString( "-ms-inline-grid" ), CSSDisplay::InlineGrid );
+}
+
+UTEST( FlexContainer, webkitFlexFooterKeepsColumnsAndVerticalLists ) {
+ Engine::instance()->createWindow( WindowSettings( 800, 600, "WebKit Flex Footer Test",
+ WindowStyle::Default, WindowBackend::Default,
+ 32, {}, 1, false, true ),
+ ContextSettings( false, 0, 0, GLv_default, true, false ) );
+ init_flex_test();
+ UISceneNode* sceneNode = SceneManager::instance()->getUISceneNode();
+
+ sceneNode->loadLayoutFromString( Tools::HTMLFormatter::HTMLtoXML( R"html(
+
+
+
+ )html" ) );
+ sceneNode->updateDirtyLayouts();
+
+ auto* footer = sceneNode->getRoot()->find( "footer" )->asType();
+ ASSERT_TRUE( footer != nullptr );
+ EXPECT_EQ( footer->getDisplay(), CSSDisplay::Flex );
+ auto columns = footer->findAllByClass( "col" );
+ ASSERT_EQ( columns.size(), (size_t)4 );
+ Float previousColumnRight = 0.f;
+ for ( auto* column : columns ) {
+ EXPECT_GE( column->getPixelsPosition().x, previousColumnRight );
+ previousColumnRight = column->getPixelsPosition().x + column->getPixelsSize().getWidth();
+
+ auto items = column->findAllByTag( "li" );
+ ASSERT_FALSE( items.empty() );
+ Float previousItemBottom = 0.f;
+ for ( auto* item : items ) {
+ EXPECT_GE( item->getPixelsPosition().y, previousItemBottom );
+ previousItemBottom = item->getPixelsPosition().y + item->getPixelsSize().getHeight();
+ }
+ }
+
+ Engine::destroySingleton();
+}
+
// ─────────────────────────────────────────────────────────────────────────────
// Phase 1: Item Collection
// ─────────────────────────────────────────────────────────────────────────────
diff --git a/src/tests/unit_tests/uihtml_tests.cpp b/src/tests/unit_tests/uihtml_tests.cpp
index fc9674bca..d21794471 100644
--- a/src/tests/unit_tests/uihtml_tests.cpp
+++ b/src/tests/unit_tests/uihtml_tests.cpp
@@ -314,6 +314,7 @@ UTEST( UIHTML, redditOldThreadWebViewSmoke ) {
auto flairCheckbox = documentRoot->find( "flair_enabled" );
auto commentButtons =
documentRoot->querySelector( "#thing_t1_on791mh > .entry > .flat-list.buttons" );
+ auto redditFooter = documentRoot->querySelector( ".footer-parent > .footer" );
ASSERT_TRUE( side != nullptr );
ASSERT_TRUE( siteTable != nullptr );
@@ -345,6 +346,18 @@ UTEST( UIHTML, redditOldThreadWebViewSmoke ) {
ASSERT_TRUE( commentContentPolicy != nullptr );
ASSERT_TRUE( flairCheckbox != nullptr );
ASSERT_TRUE( commentButtons != nullptr );
+ ASSERT_TRUE( redditFooter != nullptr );
+ EXPECT_EQ( redditFooter->asType()->getDisplay(), CSSDisplay::Flex );
+ Float footerColumnRight = 0.f;
+ for ( auto* col : redditFooter->findAllByClass( "col" ) ) {
+ EXPECT_GE( col->getPixelsPosition().x, footerColumnRight );
+ footerColumnRight = col->getPixelsPosition().x + col->getPixelsSize().getWidth();
+ Float footerItemBottom = 0.f;
+ for ( auto* li : col->querySelectorAll( "li" ) ) {
+ EXPECT_GE( li->getPixelsPosition().y, footerItemBottom );
+ footerItemBottom = li->getPixelsPosition().y + li->getPixelsSize().getHeight();
+ }
+ }
Float commentButtonRight = 0.f;
for ( auto* li : commentButtons->findAllByTag( "li" ) ) {
ASSERT_TRUE( li->findByTag( "a" ) != nullptr );