diff --git a/src/eepp/ui/flexlayouter.cpp b/src/eepp/ui/flexlayouter.cpp index 381282612..49e70bd3f 100644 --- a/src/eepp/ui/flexlayouter.cpp +++ b/src/eepp/ui/flexlayouter.cpp @@ -1222,6 +1222,14 @@ void FlexLayouter::updateLayout() { if ( widget->isInline() || mPacking ) return; + RichText* richText = widget->isType( UI_TYPE_RICHTEXT ) + ? widget->asType()->getRichTextPtr() + : nullptr; + bool preserveFloatConstrainedBFCWidth = + widget->establishesBlockFormattingContext() && + widget->getLayoutWidthPolicy() == SizePolicy::MatchParent && richText != nullptr && + !richText->getExternalFloatExclusions().empty(); + mPacking = true; mContainer->beginAttributesTransaction(); @@ -1230,7 +1238,7 @@ void FlexLayouter::updateLayout() { auto* parent = mContainer->getParent(); bool parentIsFlexContainer = parent && parent->isType( UI_TYPE_HTML_WIDGET ) && static_cast( parent )->isFlex(); - if ( !parentIsFlexContainer ) + if ( !parentIsFlexContainer && !preserveFloatConstrainedBFCWidth ) setMatchParentIfNeededVerticalGrowth(); } @@ -1333,6 +1341,8 @@ void FlexLayouter::updateLayout() { containerPadding.Right ); else if ( widthPolicy == SizePolicy::Fixed ) mContainer->setInternalPixelsWidth( containerWidth ); + else if ( preserveFloatConstrainedBFCWidth ) + mContainer->setInternalPixelsWidth( containerWidth ); else mContainer->setInternalPixelsWidth( mContainer->getParent() @@ -1355,6 +1365,8 @@ void FlexLayouter::updateLayout() { mContainer->setInternalPixelsWidth( totW ); else if ( widthPolicy == SizePolicy::Fixed ) mContainer->setInternalPixelsWidth( containerWidth ); + else if ( preserveFloatConstrainedBFCWidth ) + mContainer->setInternalPixelsWidth( containerWidth ); else mContainer->setInternalPixelsWidth( mContainer->getParent() ? mContainer->getParent()->getPixelsSize().getWidth() @@ -1403,6 +1415,13 @@ void FlexLayouter::updateLayout() { applyLayout( lines, mainAxis, crossAxis, containerPadding, containerWidth, containerHeight, widthPolicy, heightPolicy ); + if ( preserveFloatConstrainedBFCWidth ) { + // The parent RichText stream has already resolved this match-parent BFC against active + // floats and placed it into a narrowed atomic fragment. Flex layout still needs to run + // using that used width, but its normal match-parent finalization would expand back to + // the full parent content box and overlap the float. + mContainer->setInternalPixelsWidth( containerWidth ); + } // CSS Flexbox ยง8.5: store the container's baseline for use by outer flex containers. // For row/row-reverse, baseline = first flex line's baseline offset from content top. diff --git a/src/tests/unit_tests/uihtml_tests.cpp b/src/tests/unit_tests/uihtml_tests.cpp index 215149ea9..ada1af977 100644 --- a/src/tests/unit_tests/uihtml_tests.cpp +++ b/src/tests/unit_tests/uihtml_tests.cpp @@ -3745,6 +3745,70 @@ UTEST( UIHTML, PaddedHeaderWithNestedFloatsDoesNotOverlapClearedMain ) { Engine::destroySingleton(); } +UTEST( UIHTML, FlexInfobarAvoidsRightFloat ) { + auto win = Engine::instance()->createWindow( + WindowSettings( 800, 600, "flex infobar avoids right float", WindowStyle::Default, + WindowBackend::Default, 32, {}, 1, false, true ), + ContextSettings( false, 0, 0, GLv_default, true, false ) ); + FileSystem::changeWorkingDirectory( Sys::getProcessPath() ); + + UI::UISceneNode* sceneNode = init_test_inline_block(); + sceneNode->loadLayoutFromString( HTMLFormatter::HTMLtoXML( R"html( + + + + + +
+ + + + )html" ) ); + win->getInput()->update(); + SceneManager::instance()->update(); + sceneNode->updateDirtyLayouts(); + sceneNode->updateDirtyLayouts(); + + auto* side = sceneNode->getRoot()->find( "side" )->asType(); + auto* infobar = sceneNode->getRoot()->find( "infobar" )->asType(); + ASSERT_TRUE( side != nullptr ); + ASSERT_TRUE( infobar != nullptr ); + + const Float sideLeft = side->convertToWorldSpace( { 0, 0 } ).x; + const Float infobarRight = + infobar->convertToWorldSpace( { 0, 0 } ).x + infobar->getPixelsSize().getWidth(); + + EXPECT_LE( infobarRight, sideLeft + 0.5f ); + + Engine::destroySingleton(); +} + UTEST( UIHTML, AnchorsSizing ) { auto win = Engine::instance()->createWindow( WindowSettings( 1024, 653, "anchors sizing", WindowStyle::Default, WindowBackend::Default,