diff --git a/src/eepp/ui/uirichtext.cpp b/src/eepp/ui/uirichtext.cpp index 9c4c62e8c..a245961b1 100644 --- a/src/eepp/ui/uirichtext.cpp +++ b/src/eepp/ui/uirichtext.cpp @@ -238,6 +238,7 @@ bool UIHTMLBody::applyProperty( const StyleSheetProperty& attribute ) { } case PropertyId::MinHeight: mMinHeightLocal = attribute.asStyleSheetLength(); + updateDocumentMinHeight(); return true; default: break; @@ -309,6 +310,10 @@ void UIHTMLBody::updateDocumentMinHeight() { // 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 } ); + else if ( minHeight > oldMinHeight && + getPixelsSize().getHeight() < PixelDensity::dpToPx( minHeight ) ) + // Raising min-height must expand the body to the new minimum when it is currently smaller. + setPixelsSize( { getPixelsSize().getWidth(), PixelDensity::dpToPx( minHeight ) } ); } void UIHTMLBody::updateDocumentContentMinHeightFromChildren() { diff --git a/src/eepp/ui/uiscenenode.cpp b/src/eepp/ui/uiscenenode.cpp index 8b630b984..4cdb31d74 100644 --- a/src/eepp/ui/uiscenenode.cpp +++ b/src/eepp/ui/uiscenenode.cpp @@ -789,7 +789,7 @@ void UISceneNode::setViewportPixelsSize( const Sizef& size ) { mViewportPixelsSize = size; mHasViewportPixelsSize = true; - mRoot->setPixelsSize( mViewportPixelsSize ); + mRoot->setPixelsSize( getPixelsSize() ); onViewportPixelsSizeChange(); } @@ -798,6 +798,7 @@ void UISceneNode::clearViewportPixelsSize() { return; mHasViewportPixelsSize = false; + mRoot->setPixelsSize( getPixelsSize() ); onViewportPixelsSizeChange(); } @@ -1195,7 +1196,7 @@ void UISceneNode::onChildCountChange( Node* child, const bool& removed ) { void UISceneNode::onSizeChange() { SceneNode::onSizeChange(); - mRoot->setPixelsSize( getViewportPixelsSize() ); + mRoot->setPixelsSize( getPixelsSize() ); } void UISceneNode::processStyleSheetAtRules( const StyleSheet& styleSheet, URI baseURI ) { diff --git a/src/eepp/ui/uiwebview.cpp b/src/eepp/ui/uiwebview.cpp index ed81fa007..f4c8542b1 100644 --- a/src/eepp/ui/uiwebview.cpp +++ b/src/eepp/ui/uiwebview.cpp @@ -157,11 +157,12 @@ void UIWebView::onSizeChange() { void UIWebView::updateHTMLMinHeight( UIHTMLHtml* html, UIHTMLBody* body ) { Sizef viewport = mDocumentScene ? mDocumentScene->getViewportPixelsSize() : getPixelsSize(); - Float h = PixelDensity::pxToDp( viewport.getHeight() ); + const Float h = PixelDensity::pxToDp( viewport.getHeight() ); + const Rectf bodyMargin = body->getLayoutPixelsMargin(); + const Float bodyMarginHeight = PixelDensity::pxToDp( bodyMargin.Top + bodyMargin.Bottom ); html->setMinHeight( h ); - body->setMinHeight( h ); html->setPixelsSize( viewport ); - body->setPixelsSize( viewport ); + body->setDocumentViewportMinHeight( eemax( 0.f, h - bodyMarginHeight ) ); } void UIWebView::onSceneChange() { @@ -500,8 +501,10 @@ void UIWebView::updateDocumentSceneContentExtent() { } bool extentChanged = extent != Sizef::Zero && extent != mDocumentScene->getPixelsSize(); - if ( extentChanged ) + if ( extentChanged ) { mDocumentScene->setPixelsSize( extent ); + updateHTMLMinHeightForDocument(); + } mUpdatingDocumentContentExtent = false; @@ -510,8 +513,8 @@ void UIWebView::updateDocumentSceneContentExtent() { viewport != Sizef::Zero && viewport != mDocumentScene->getViewportPixelsSize(); if ( ( viewportChanged || extentChanged ) && !mDocumentViewportSyncQueued ) { mDocumentViewportSyncQueued = true; - runOnMainThread( [this]() { - runOnMainThread( [this]() { + runOnMainThread( [this] { + runOnMainThread( [this] { mDocumentViewportSyncQueued = false; onDocumentViewportGeometryChanged(); } ); diff --git a/src/tests/unit_tests/uihtml_tests.cpp b/src/tests/unit_tests/uihtml_tests.cpp index 8f79fe714..dddf8e886 100644 --- a/src/tests/unit_tests/uihtml_tests.cpp +++ b/src/tests/unit_tests/uihtml_tests.cpp @@ -4042,6 +4042,8 @@ UTEST( UIHTML, TextureReplaceInvalidatesRichTextAncestors ) { webView->setParent( sceneNode->getRoot() ); webView->setPixelsSize( win->getWidth(), win->getHeight() ); webView->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed ); + UISceneNode* documentScene = webView->getDocumentSceneNode(); + ASSERT_TRUE( documentScene != nullptr ); std::string html = R"html( @@ -4054,19 +4056,19 @@ UTEST( UIHTML, TextureReplaceInvalidatesRichTextAncestors ) { )html"; - sceneNode->setURI( "file://delayed-image-resize.html" ); - sceneNode->loadLayoutFromString( HTMLFormatter::HTMLtoXML( html ), - webView->getDocumentContainer(), - String::hash( "delayed-image-resize" ) ); + documentScene->setURI( "file://delayed-image-resize.html" ); + documentScene->loadLayoutFromString( HTMLFormatter::HTMLtoXML( html ), + webView->getDocumentContainer(), + String::hash( "delayed-image-resize" ) ); win->getInput()->update(); SceneManager::instance()->update(); - sceneNode->updateDirtyLayouts(); + documentScene->updateDirtyLayouts(); - auto* article = sceneNode->getRoot()->find( "article" )->asType(); - auto* body = sceneNode->getRoot()->findByType( UI_TYPE_HTML_BODY )->asType(); + auto* article = documentScene->getRoot()->find( "article" )->asType(); + auto* body = documentScene->getRoot()->findByType( UI_TYPE_HTML_BODY )->asType(); auto* doc = webView->getDocumentContainer(); - auto images = sceneNode->getRoot()->findAllByTag( "img" ); + auto images = documentScene->getRoot()->findAllByTag( "img" ); ASSERT_TRUE( article != nullptr ); ASSERT_TRUE( body != nullptr ); ASSERT_TRUE( doc != nullptr ); @@ -4078,7 +4080,7 @@ UTEST( UIHTML, TextureReplaceInvalidatesRichTextAncestors ) { TextureFactory::instance()->createEmptyTexture( 1, 1, 4, Color::Transparent ); ASSERT_TRUE( texture != nullptr ); img->setDrawable( texture ); - sceneNode->updateDirtyLayouts(); + documentScene->updateDirtyLayouts(); Float articleInitialHeight = article->getPixelsSize().getHeight(); Float bodyInitialHeight = body->getPixelsSize().getHeight(); @@ -4087,7 +4089,7 @@ UTEST( UIHTML, TextureReplaceInvalidatesRichTextAncestors ) { Image loadedImage( 320, 180, 4, Color::White ); texture->replace( &loadedImage ); SceneManager::instance()->update(); - sceneNode->updateDirtyLayouts(); + documentScene->updateDirtyLayouts(); EXPECT_GT( article->getPixelsSize().getHeight(), articleInitialHeight + 150.f ); EXPECT_GT( body->getPixelsSize().getHeight(), bodyInitialHeight + 150.f ); @@ -4108,6 +4110,8 @@ UTEST( UIHTML, HtmlContainsTableBodyHeight ) { webView->setParent( sceneNode->getRoot() ); webView->setPixelsSize( win->getWidth(), win->getHeight() ); webView->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed ); + UISceneNode* documentScene = webView->getDocumentSceneNode(); + ASSERT_TRUE( documentScene != nullptr ); FileSystem::changeWorkingDirectory( Sys::getProcessPath() ); std::string html; @@ -4119,14 +4123,14 @@ UTEST( UIHTML, HtmlContainsTableBodyHeight ) { html.erase( pos, end + 2 - pos ); } - sceneNode->setURI( "file://html-table-body-height.html" ); - sceneNode->loadLayoutFromString( HTMLFormatter::HTMLtoXML( html ), - webView->getDocumentContainer(), - String::hash( "html-table-body-height" ) ); + documentScene->setURI( "file://html-table-body-height.html" ); + documentScene->loadLayoutFromString( HTMLFormatter::HTMLtoXML( html ), + webView->getDocumentContainer(), + String::hash( "html-table-body-height" ) ); win->getInput()->update(); SceneManager::instance()->update(); - sceneNode->updateDirtyLayouts(); + documentScene->updateDirtyLayouts(); std::string css; ASSERT_TRUE( FileSystem::fileGet( "assets/html/base.css", css ) ); @@ -4134,16 +4138,18 @@ UTEST( UIHTML, HtmlContainsTableBodyHeight ) { std::string newsCss; ASSERT_TRUE( FileSystem::fileGet( "assets/html/news.css", newsCss ) ); css += newsCss; - sceneNode->runOnMainThread( [sceneNode, css = std::move( css )] { - sceneNode->combineStyleSheet( css, true, - String::hash( "html-table-body-height-late-css" ) ); + documentScene->runOnMainThread( [documentScene, css = std::move( css )] { + documentScene->combineStyleSheet( css, true, + String::hash( "html-table-body-height-late-css" ) ); } ); SceneManager::instance()->update(); - sceneNode->updateDirtyLayouts(); + documentScene->updateDirtyLayouts(); + SceneManager::instance()->update(); + documentScene->updateDirtyLayouts(); - auto* htmlNode = sceneNode->getRoot()->findByType( UI_TYPE_HTML_HTML )->asType(); - auto* body = sceneNode->getRoot()->findByType( UI_TYPE_HTML_BODY )->asType(); - auto* table = sceneNode->getRoot()->find( "hnmain" )->asType(); + auto* htmlNode = documentScene->getRoot()->findByType( UI_TYPE_HTML_HTML )->asType(); + auto* body = documentScene->getRoot()->findByType( UI_TYPE_HTML_BODY )->asType(); + auto* table = documentScene->getRoot()->find( "hnmain" )->asType(); ASSERT_TRUE( htmlNode != nullptr ); ASSERT_TRUE( body != nullptr ); ASSERT_TRUE( table != nullptr ); @@ -4167,6 +4173,8 @@ UTEST( UIHTML, BodyDocumentContentMinHeightCanShrink ) { webView->setParent( sceneNode->getRoot() ); webView->setPixelsSize( win->getWidth(), win->getHeight() ); webView->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed ); + UISceneNode* documentScene = webView->getDocumentSceneNode(); + ASSERT_TRUE( documentScene != nullptr ); std::string html = R"html( @@ -4177,19 +4185,19 @@ UTEST( UIHTML, BodyDocumentContentMinHeightCanShrink ) { )html"; - sceneNode->setURI( "file://body-content-min-height-shrink.html" ); - sceneNode->loadLayoutFromString( HTMLFormatter::HTMLtoXML( html ), - webView->getDocumentContainer(), - String::hash( "body-content-min-height-shrink" ) ); + documentScene->setURI( "file://body-content-min-height-shrink.html" ); + documentScene->loadLayoutFromString( HTMLFormatter::HTMLtoXML( html ), + webView->getDocumentContainer(), + String::hash( "body-content-min-height-shrink" ) ); webView->refreshDocumentLayout(); win->getInput()->update(); SceneManager::instance()->update(); - sceneNode->updateDirtyLayouts(); + documentScene->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(); + auto* htmlNode = documentScene->getRoot()->findByType( UI_TYPE_HTML_HTML )->asType(); + auto* body = documentScene->getRoot()->findByType( UI_TYPE_HTML_BODY )->asType(); + auto* spacer = documentScene->getRoot()->find( "spacer" )->asType(); ASSERT_TRUE( htmlNode != nullptr ); ASSERT_TRUE( body != nullptr ); ASSERT_TRUE( spacer != nullptr ); @@ -4201,10 +4209,10 @@ UTEST( UIHTML, BodyDocumentContentMinHeightCanShrink ) { spacer->setStyleSheetProperty( StyleSheetProperty( "height", "120px" ) ); win->getInput()->update(); SceneManager::instance()->update(); - sceneNode->updateDirtyLayouts(); + documentScene->updateDirtyLayouts(); win->getInput()->update(); SceneManager::instance()->update(); - sceneNode->updateDirtyLayouts(); + documentScene->updateDirtyLayouts(); EXPECT_LT( spacer->getPixelsSize().getHeight(), 180.f ); EXPECT_LT( body->getPixelsSize().getHeight(), tallBodyHeight - 250.f ); @@ -4250,12 +4258,14 @@ UTEST( UIHTML, DeferredCSSKeepsTableHeightStableAfterViewportResize ) { webView->setStyleSheetDefaultMarker( app.getStyleSheetDefaultMarker() ); webView->loadURI( "assets/html/hn_empty_thread.html" ); - auto* bigboxTd = ui->getRoot()->querySelector( "#bigbox > td" ); - auto* bigboxTable = ui->getRoot()->querySelector( "#bigbox > td > table" ); + UISceneNode* documentScene = webView->getDocumentSceneNode(); + ASSERT_TRUE( documentScene != nullptr ); + auto* bigboxTd = documentScene->getRoot()->querySelector( "#bigbox > td" ); + auto* bigboxTable = documentScene->getRoot()->querySelector( "#bigbox > td > table" ); ASSERT_TRUE( bigboxTd != nullptr ); ASSERT_TRUE( bigboxTable != nullptr ); - auto* titleCell = ui->getRoot()->querySelector( ".title" ); + auto* titleCell = documentScene->getRoot()->querySelector( ".title" ); ASSERT_TRUE( titleCell != nullptr ); ASSERT_TRUE( titleCell->isType( UI_TYPE_RICHTEXT ) ); diff --git a/src/tests/unit_tests/uiwebview_tests.cpp b/src/tests/unit_tests/uiwebview_tests.cpp index 3a08a9d86..5ccd03789 100644 --- a/src/tests/unit_tests/uiwebview_tests.cpp +++ b/src/tests/unit_tests/uiwebview_tests.cpp @@ -362,8 +362,8 @@ UTEST( UIWebView, ResponsiveDocumentShrinksAfterGrowResize ) { EXPECT_LT( fill->getPixelsSize().getWidth(), grownFillWidth ); EXPECT_NEAR( fill->getPixelsSize().getWidth(), documentScene->getViewportPixelsSize().getWidth(), 0.5f ); - EXPECT_NEAR( html->getPixelsSize().getWidth(), - documentScene->getViewportPixelsSize().getWidth(), 0.5f ); + EXPECT_NEAR( html->getPixelsSize().getWidth(), documentScene->getPixelsSize().getWidth(), + 0.5f ); EXPECT_NEAR( body->getPixelsSize().getWidth(), documentScene->getViewportPixelsSize().getWidth(), 0.5f ); EXPECT_FALSE( webView->getHorizontalScrollBar()->isVisible() ); @@ -443,11 +443,11 @@ UTEST( UIWebView, HorizontalScrollDisappearsAfterResponsiveShrink ) { ASSERT_TRUE( html != nullptr ); ASSERT_TRUE( body != nullptr ); EXPECT_NEAR( documentScene->getRoot()->getPixelsSize().getWidth(), - documentScene->getViewportPixelsSize().getWidth(), 0.5f ); + documentScene->getPixelsSize().getWidth(), 0.5f ); EXPECT_NEAR( fit->getPixelsSize().getWidth(), documentScene->getViewportPixelsSize().getWidth(), 0.5f ); - EXPECT_NEAR( html->getPixelsSize().getWidth(), - documentScene->getViewportPixelsSize().getWidth(), 0.5f ); + EXPECT_NEAR( html->getPixelsSize().getWidth(), documentScene->getPixelsSize().getWidth(), + 0.5f ); EXPECT_NEAR( body->getPixelsSize().getWidth(), documentScene->getViewportPixelsSize().getWidth(), 0.5f ); EXPECT_NEAR( documentScene->getPixelsSize().getWidth(), @@ -718,9 +718,9 @@ UTEST( UIWebView, HackerNewsFrontPageBottomIsReachable ) { EXPECT_GE( documentScene->getPixelsSize().getWidth(), documentScene->getViewportPixelsSize().getWidth() ); EXPECT_NEAR( documentScene->getRoot()->getPixelsSize().getWidth(), - documentScene->getViewportPixelsSize().getWidth(), 0.5f ); - EXPECT_NEAR( html->fitMinMaxSizePx( html->getPixelsSize() ).getWidth(), - documentScene->getViewportPixelsSize().getWidth(), 0.5f ); + documentScene->getPixelsSize().getWidth(), 0.5f ); + EXPECT_NEAR( html->getPixelsSize().getWidth(), documentScene->getPixelsSize().getWidth(), + 0.5f ); EXPECT_NEAR( documentScene->getPixelsSize().getHeight(), html->fitMinMaxSizePx( html->getPixelsSize() ).getHeight(), 0.5f ); @@ -740,9 +740,9 @@ UTEST( UIWebView, HackerNewsFrontPageBottomIsReachable ) { EXPECT_GE( documentScene->getPixelsSize().getWidth(), documentScene->getViewportPixelsSize().getWidth() ); EXPECT_NEAR( documentScene->getRoot()->getPixelsSize().getWidth(), - documentScene->getViewportPixelsSize().getWidth(), 0.5f ); - EXPECT_NEAR( html->fitMinMaxSizePx( html->getPixelsSize() ).getWidth(), - documentScene->getViewportPixelsSize().getWidth(), 0.5f ); + documentScene->getPixelsSize().getWidth(), 0.5f ); + EXPECT_NEAR( html->getPixelsSize().getWidth(), documentScene->getPixelsSize().getWidth(), + 0.5f ); EXPECT_NEAR( documentScene->getPixelsSize().getHeight(), html->fitMinMaxSizePx( html->getPixelsSize() ).getHeight(), 0.5f ); viewportHeight = webView->getContainer()->getPixelsSize().getHeight(); @@ -758,9 +758,9 @@ UTEST( UIWebView, HackerNewsFrontPageBottomIsReachable ) { EXPECT_GE( documentScene->getPixelsSize().getWidth(), documentScene->getViewportPixelsSize().getWidth() ); EXPECT_NEAR( documentScene->getRoot()->getPixelsSize().getWidth(), - documentScene->getViewportPixelsSize().getWidth(), 0.5f ); - EXPECT_NEAR( html->fitMinMaxSizePx( html->getPixelsSize() ).getWidth(), - documentScene->getViewportPixelsSize().getWidth(), 0.5f ); + documentScene->getPixelsSize().getWidth(), 0.5f ); + EXPECT_NEAR( html->getPixelsSize().getWidth(), documentScene->getPixelsSize().getWidth(), + 0.5f ); EXPECT_NEAR( documentScene->getPixelsSize().getHeight(), html->fitMinMaxSizePx( html->getPixelsSize() ).getHeight(), 0.5f ); viewportHeight = webView->getContainer()->getPixelsSize().getHeight(); @@ -774,6 +774,15 @@ UTEST( UIWebView, HackerNewsFrontPageBottomIsReachable ) { EXPECT_GT( inputRect.Bottom, containerRect.Top ); EXPECT_NEAR( -documentScene->getPosition().y + viewportHeight, documentScene->getPixelsSize().getHeight(), 1.f ); + EXPECT_NEAR( documentScene->getRoot()->getPixelsSize().getHeight(), + documentScene->getPixelsSize().getHeight(), 0.5f ); + + const Vector2f inputCenter( inputRect.Left + inputRect.getWidth() * 0.5f, + inputRect.Top + inputRect.getHeight() * 0.5f ); + Node* hitNode = sceneNode->overFind( inputCenter ); + ASSERT_TRUE( hitNode != nullptr ); + EXPECT_TRUE( hitNode == documentScene->getRoot() || + documentScene->getRoot()->isParentOf( hitNode ) ); Engine::destroySingleton(); EE::Graphics::PixelDensity::setPixelDensity( 1.0f ); @@ -838,7 +847,7 @@ UTEST( UIWebView, NavigationAfterGrowDoesNotKeepMaximizedWidthOnShrink ) { webView->getContainer()->getPixelsSize().getWidth(), 0.5f ); EXPECT_LT( documentScene->getViewportPixelsSize().getWidth(), 900.f ); EXPECT_NEAR( documentScene->getRoot()->getPixelsSize().getWidth(), - documentScene->getViewportPixelsSize().getWidth(), 0.5f ); + documentScene->getPixelsSize().getWidth(), 0.5f ); EXPECT_LT( html->fitMinMaxSizePx( html->getPixelsSize() ).getWidth(), 900.f ); EXPECT_LT( body->fitMinMaxSizePx( body->getPixelsSize() ).getWidth(), 900.f ); EXPECT_LT( documentScene->getPixelsSize().getWidth(), 900.f ); @@ -898,7 +907,7 @@ UTEST( UIWebView, LayoutDrivenResizeKeepsDocumentRootAtViewport ) { pump(); EXPECT_GT( documentScene->getViewportPixelsSize().getWidth(), 2000.f ); EXPECT_NEAR( documentScene->getRoot()->getPixelsSize().getWidth(), - documentScene->getViewportPixelsSize().getWidth(), 0.5f ); + documentScene->getPixelsSize().getWidth(), 0.5f ); webView->loadURI( URI( "file://" + Sys::getProcessPath() + "assets/html/hn_frontpage.html" ) ); pump(); @@ -913,7 +922,7 @@ UTEST( UIWebView, LayoutDrivenResizeKeepsDocumentRootAtViewport ) { ASSERT_TRUE( body != nullptr ); EXPECT_LT( documentScene->getViewportPixelsSize().getWidth(), 900.f ); EXPECT_NEAR( documentScene->getRoot()->getPixelsSize().getWidth(), - documentScene->getViewportPixelsSize().getWidth(), 0.5f ); + documentScene->getPixelsSize().getWidth(), 0.5f ); EXPECT_NEAR( html->getPixelsSize().getWidth(), documentScene->getViewportPixelsSize().getWidth(), 0.5f ); EXPECT_LE( body->getPixelsSize().getWidth(),