diff --git a/include/eepp/ui/uirichtext.hpp b/include/eepp/ui/uirichtext.hpp index 8c178c372..ca89eb81f 100644 --- a/include/eepp/ui/uirichtext.hpp +++ b/include/eepp/ui/uirichtext.hpp @@ -256,9 +256,9 @@ class EE_API UIHTMLBody : public UIRichText { UIHTMLBody( const std::string& tag = "body" ); Float getLocalMinHeight() const; - void setDocumentContentMinHeight( const Float& height ); - void updateDocumentMinHeight(); - void updateDocumentContentMinHeightFromChildren(); + bool setDocumentContentMinHeight( const Float& height ); + bool updateDocumentMinHeight(); + bool updateDocumentContentMinHeightFromChildren(); virtual Uint32 onMessage( const NodeMessage* Msg ); }; diff --git a/src/eepp/ui/uirichtext.cpp b/src/eepp/ui/uirichtext.cpp index 9c4c62e8c..d3219048b 100644 --- a/src/eepp/ui/uirichtext.cpp +++ b/src/eepp/ui/uirichtext.cpp @@ -291,27 +291,33 @@ Float UIHTMLBody::getLocalMinHeight() const { return convertLengthAsDp( mMinHeightLocal, parentHeight ); } -void UIHTMLBody::setDocumentContentMinHeight( const Float& height ) { +bool UIHTMLBody::setDocumentContentMinHeight( const Float& height ) { if ( mDocumentContentMinHeight == height ) - return; + return false; mDocumentContentMinHeight = height; - updateDocumentMinHeight(); + return updateDocumentMinHeight(); } -void UIHTMLBody::updateDocumentMinHeight() { +bool UIHTMLBody::updateDocumentMinHeight() { const Float oldMinHeight = getCurMinSize().getHeight(); Float minHeight = std::max( { getLocalMinHeight(), mDocumentViewportMinHeight, mDocumentContentMinHeight } ); setMinHeight( minHeight ); + bool minHeightChanged = minHeight != oldMinHeight; + bool sizeForced = false; if ( minHeight < oldMinHeight && - getPixelsSize().getHeight() > PixelDensity::dpToPx( minHeight ) ) + getPixelsSize().getHeight() > PixelDensity::dpToPx( minHeight ) ) { // Lowering min-height does not shrink the current box by itself. Reapply size through // min/max fitting so the body can settle at the new floor. setPixelsSize( { getPixelsSize().getWidth(), 0 } ); + sizeForced = true; + } + + return minHeightChanged || sizeForced; } -void UIHTMLBody::updateDocumentContentMinHeightFromChildren() { +bool UIHTMLBody::updateDocumentContentMinHeightFromChildren() { Float maxH = 0; Node* child = mChild; @@ -331,7 +337,7 @@ void UIHTMLBody::updateDocumentContentMinHeightFromChildren() { child = child->getNextNode(); } - setDocumentContentMinHeight( maxH > 0 ? std::trunc( PixelDensity::pxToDp( maxH ) ) : 0 ); + return setDocumentContentMinHeight( maxH > 0 ? std::trunc( PixelDensity::pxToDp( maxH ) ) : 0 ); } Uint32 UIHTMLBody::onMessage( const NodeMessage* Msg ) { @@ -340,10 +346,10 @@ Uint32 UIHTMLBody::onMessage( const NodeMessage* Msg ) { if ( Msg->getMsg() == NodeMessage::LayoutAttributeChange && Msg->getSender() != this && !mSettingBodyHeight ) { mSettingBodyHeight = true; - updateDocumentContentMinHeightFromChildren(); + bool documentMinHeightChanged = updateDocumentContentMinHeightFromChildren(); mSettingBodyHeight = false; - if ( getParent() && getParent()->isType( UI_TYPE_HTML_HTML ) ) + if ( documentMinHeightChanged && getParent() && getParent()->isType( UI_TYPE_HTML_HTML ) ) getParent()->asType()->setLayoutDirty( LayoutInvalidation::Document ); } diff --git a/src/tests/unit_tests/uihtml_tests.cpp b/src/tests/unit_tests/uihtml_tests.cpp index fbc29f507..859c4424c 100644 --- a/src/tests/unit_tests/uihtml_tests.cpp +++ b/src/tests/unit_tests/uihtml_tests.cpp @@ -4173,6 +4173,60 @@ UTEST( UIHTML, BodyDocumentContentMinHeightCanShrink ) { Engine::destroySingleton(); } +UTEST( UIHTML, BodyNoOpContentHeightChangeDoesNotDirtyHtml ) { + auto win = Engine::instance()->createWindow( + WindowSettings( 800, 600, "body no-op content height change", WindowStyle::Default, + WindowBackend::Default, 32, {}, 1, false, true ), + ContextSettings( false, 0, 0, GLv_default, true, false ) ); + + UISceneNode* sceneNode = init_test_inline_block(); + + UIWebView* webView = UIWebView::New(); + webView->setParent( sceneNode->getRoot() ); + webView->setPixelsSize( win->getWidth(), win->getHeight() ); + webView->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed ); + + std::string html = R"html( + + + +
+ + + )html"; + + sceneNode->setURI( "file://body-no-op-content-height-change.html" ); + sceneNode->loadLayoutFromString( HTMLFormatter::HTMLtoXML( html ), + webView->getDocumentContainer(), + String::hash( "body-no-op-content-height-change" ) ); + webView->refreshDocumentLayout(); + + win->getInput()->update(); + SceneManager::instance()->update(); + sceneNode->updateDirtyLayouts(); + win->getInput()->update(); + SceneManager::instance()->update(); + sceneNode->updateDirtyLayouts(); + + auto* htmlNode = sceneNode->getRoot()->findByType( UI_TYPE_HTML_HTML )->asType(); + auto* body = sceneNode->getRoot()->findByType( UI_TYPE_HTML_BODY )->asType(); + auto* spacer = sceneNode->getRoot()->find( "spacer" )->asType(); + ASSERT_TRUE( htmlNode != nullptr ); + ASSERT_TRUE( body != nullptr ); + ASSERT_TRUE( spacer != nullptr ); + ASSERT_GT( body->getPixelsSize().getHeight(), 850.f ); + ASSERT_FALSE( htmlNode->isLayoutDirty() ); + + spacer->setPixelsSize( + { spacer->getPixelsSize().getWidth() + 25.f, spacer->getPixelsSize().getHeight() } ); + EXPECT_FALSE( htmlNode->isLayoutDirty() ); + win->getInput()->update(); + SceneManager::instance()->update(); + sceneNode->updateDirtyLayouts(); + + Engine::destroySingleton(); +} + UTEST( UIHTML, DeferredCSSKeepsTableHeightStableAfterViewportResize ) { std::shared_ptr threadPool( ThreadPool::createShared( eemax( 4, Sys::getCPUCount() ) ) );