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 );