From 288950bf340ddd66e02e8e58ff98192b3c99d8cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Fri, 5 Jun 2026 00:18:26 -0300 Subject: [PATCH] Image sizing fixes. Added support for `:where` and `:is`. --- .../eepp-uihtmltable-complex-layout-3.webp | Bin 24746 -> 24778 bytes bin/unit_tests/assets/html/image_width.html | 28 +++ bin/unit_tests/assets/html/image_width_2.html | 34 +++ bin/unit_tests/assets/html/image_width_3.html | 209 ++++++++++++++++++ bin/unit_tests/assets/html/image_width_3.webp | Bin 0 -> 200 bytes src/eepp/ui/css/stylesheetselectorrule.cpp | 15 +- src/eepp/ui/css/stylesheetspecification.cpp | 22 ++ src/eepp/ui/uiimage.cpp | 11 + src/eepp/ui/uinode.cpp | 11 +- src/eepp/ui/uirichtext.cpp | 19 ++ src/eepp/ui/uiwidget.cpp | 15 +- src/tests/unit_tests/uihtml_tests.cpp | 139 ++++++++++++ 12 files changed, 493 insertions(+), 10 deletions(-) create mode 100644 bin/unit_tests/assets/html/image_width.html create mode 100644 bin/unit_tests/assets/html/image_width_2.html create mode 100644 bin/unit_tests/assets/html/image_width_3.html create mode 100644 bin/unit_tests/assets/html/image_width_3.webp diff --git a/bin/unit_tests/assets/html/eepp-uihtmltable-complex-layout-3.webp b/bin/unit_tests/assets/html/eepp-uihtmltable-complex-layout-3.webp index 1cd510a398f06bbd2b608a37c1f6746c3941072a..e48430b2863cb980055f880ce1b7597723edd6f8 100644 GIT binary patch literal 24778 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 literal 24746 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ℑ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 F{{!4X+W-In diff --git a/bin/unit_tests/assets/html/image_width.html b/bin/unit_tests/assets/html/image_width.html new file mode 100644 index 000000000..1a0681cd3 --- /dev/null +++ b/bin/unit_tests/assets/html/image_width.html @@ -0,0 +1,28 @@ + + + + +
+
+representative_image +
+
+ diff --git a/bin/unit_tests/assets/html/image_width_2.html b/bin/unit_tests/assets/html/image_width_2.html new file mode 100644 index 000000000..fdec41eaf --- /dev/null +++ b/bin/unit_tests/assets/html/image_width_2.html @@ -0,0 +1,34 @@ + + + + + + +
+ +
+ + diff --git a/bin/unit_tests/assets/html/image_width_3.html b/bin/unit_tests/assets/html/image_width_3.html new file mode 100644 index 000000000..efe93e02c --- /dev/null +++ b/bin/unit_tests/assets/html/image_width_3.html @@ -0,0 +1,209 @@ + + + + + + +
+
+
+

+ Cards on a webpage, scrolled into the viewport, completing their animation (turning to land flat), as they reach 50%. +

+
+
+
+ + diff --git a/bin/unit_tests/assets/html/image_width_3.webp b/bin/unit_tests/assets/html/image_width_3.webp new file mode 100644 index 0000000000000000000000000000000000000000..37f60622b10c8015a430dec4fc625dd5aca75b3c GIT binary patch literal 200 zcmWIYbaOkvz`zjh>J$(bVBxa`$kzXVGL4b_!o;pCOa3!5XWl-u|L #include #include +#include #include #include @@ -626,6 +627,11 @@ static bool isNth( int a, int b, int count ) { return ( x >= 0 && x * a + b == count ); } +static bool whereIsMatch( const UIWidget* node, const std::string& param ) { + StyleSheetSelectorRule rule( param, StyleSheetSelectorRule::PatternMatch::ANY ); + return rule.matches( const_cast( node ) ); +} + void StyleSheetSpecification::registerDefaultNodeSelectors() { mNodeSelectors["empty"] = []( const UIWidget* node, int, int, const FunctionString& ) -> bool { return node->getFirstChild() == NULL; @@ -739,6 +745,22 @@ void StyleSheetSpecification::registerDefaultNodeSelectors() { } return false; }; + + mNodeSelectors["where"] = []( const UIWidget* node, int, int, + const FunctionString& data ) -> bool { + if ( data.isEmpty() || data.getParameters().empty() || + ( data.getName() != "where" && data.getName() != "is" ) ) + return false; + + for ( const auto& param : data.getParameters() ) { + if ( !param.empty() && whereIsMatch( node, param ) ) + return true; + } + return false; + }; + + auto whereFn = mNodeSelectors["where"]; + mNodeSelectors["is"] = whereFn; } StructuralSelector StyleSheetSpecification::getStructuralSelector( const std::string& name ) { diff --git a/src/eepp/ui/uiimage.cpp b/src/eepp/ui/uiimage.cpp index 9635463f1..fe0780bb2 100644 --- a/src/eepp/ui/uiimage.cpp +++ b/src/eepp/ui/uiimage.cpp @@ -146,6 +146,17 @@ void UIImage::onAutoSize() { } } else if ( mHeightPolicy == SizePolicy::WrapContent ) { Float contentWidth = std::max( 0.f, size.x - mPaddingPx.Left - mPaddingPx.Right ); + + if ( !mMaxWidthEq.empty() ) { + Float maxWidth = + lengthFromValue( mMaxWidthEq, CSS::PropertyRelativeTarget::ContainingBlockWidth ); + Float maxContentWidth = std::max( 0.f, maxWidth - mPaddingPx.Left - mPaddingPx.Right ); + if ( contentWidth > maxContentWidth ) { + contentWidth = maxContentWidth; + size.x = maxWidth; + } + } + size.y = (int)( contentWidth * ( drawableSize.getHeight() / drawableSize.getWidth() ) ) + mPaddingPx.Top + mPaddingPx.Bottom; if ( !mMaxHeightEq.empty() ) { diff --git a/src/eepp/ui/uinode.cpp b/src/eepp/ui/uinode.cpp index 5ea4d6c18..382fb2dd0 100644 --- a/src/eepp/ui/uinode.cpp +++ b/src/eepp/ui/uinode.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -1634,15 +1635,17 @@ Float UINode::getPropertyRelativeTargetContainerLength( Float containerLength = defaultValue; switch ( relativeTarget ) { case PropertyRelativeTarget::ContainingBlockWidth: { - Node* parent = getParent(); // Text spans cannot be considered containing blocks - while ( parent->isType( UI_TYPE_TEXTSPAN ) ) + Node* parent = getParent(); + while ( parent && parent->isWidget() && parent->isType( UI_TYPE_HTML_WIDGET ) && + static_cast( parent )->isInline() ) parent = parent->getParent(); containerLength = parent ? parent->getPixelsSize().getWidth() : 0; break; } case PropertyRelativeTarget::ContainingBlockHeight: { - Node* parent = getParent(); // Text spans cannot be considered containing blocks - while ( parent->isType( UI_TYPE_TEXTSPAN ) ) + Node* parent = getParent(); + while ( parent && parent->isWidget() && parent->isType( UI_TYPE_HTML_WIDGET ) && + static_cast( parent )->isInline() ) parent = parent->getParent(); containerLength = parent ? parent->getPixelsSize().getHeight() : 0; break; diff --git a/src/eepp/ui/uirichtext.cpp b/src/eepp/ui/uirichtext.cpp index 5f4863144..e0b3b70ff 100644 --- a/src/eepp/ui/uirichtext.cpp +++ b/src/eepp/ui/uirichtext.cpp @@ -1961,6 +1961,25 @@ void UIRichText::rebuildRichText( UILayout* container, RichText& richText, Intri if ( widget->isType( UI_TYPE_TEXTSPAN ) && widget->asType()->isInlineBlock() ) widget->asType()->updateLayout(); + + if ( widget->getLayoutWidthPolicy() == SizePolicy::Fixed && + widget->getUIStyle() ) { + const StyleSheetProperty* wprop = + widget->getUIStyle()->getProperty( PropertyId::Width ); + if ( wprop && StyleSheetLength::isPercentage( wprop->value() ) ) { + widget->setPixelsSize( { widget->lengthFromValue( *wprop ), + widget->getPixelsSize().getHeight() } ); + } + } + if ( widget->getLayoutHeightPolicy() == SizePolicy::Fixed && + widget->getUIStyle() ) { + const StyleSheetProperty* hprop = + widget->getUIStyle()->getProperty( PropertyId::Height ); + if ( hprop && StyleSheetLength::isPercentage( hprop->value() ) ) { + widget->setPixelsSize( { widget->getPixelsSize().getWidth(), + widget->lengthFromValue( *hprop ) } ); + } + } } Sizef size; diff --git a/src/eepp/ui/uiwidget.cpp b/src/eepp/ui/uiwidget.cpp index 20097f4cc..779f00ccd 100644 --- a/src/eepp/ui/uiwidget.cpp +++ b/src/eepp/ui/uiwidget.cpp @@ -1875,6 +1875,16 @@ std::string UIWidget::getPropertyString( const PropertyDefinition* propertyDef, : "false"; case PropertyId::Focusable: return isTabFocusable() ? "true" : "false"; + case PropertyId::Class: { + std::string cls; + const auto& classes = getStyleSheetClasses(); + for ( size_t i = 0; i < classes.size(); i++ ) { + if ( i > 0 ) + cls += ' '; + cls += classes[i]; + } + return cls; + } default: break; } @@ -2464,8 +2474,9 @@ void UIWidget::loadFromXmlNode( const pugi::xml_node& node ) { } // Create a property without trimming its value - StyleSheetProperty prop( ait->name(), ait->value(), false, - StyleSheetSelectorRule::SpecificityInline ); + Uint64 specificity = + ( mFlags & UI_HTML_ELEMENT ) ? 0 : StyleSheetSelectorRule::SpecificityInline; + StyleSheetProperty prop( ait->name(), ait->value(), false, specificity ); if ( prop.getShorthandDefinition() != NULL ) { auto properties = prop.getShorthandDefinition()->parse( ait->value() ); diff --git a/src/tests/unit_tests/uihtml_tests.cpp b/src/tests/unit_tests/uihtml_tests.cpp index 8e05ffcea..a18c80a95 100644 --- a/src/tests/unit_tests/uihtml_tests.cpp +++ b/src/tests/unit_tests/uihtml_tests.cpp @@ -3936,3 +3936,142 @@ UTEST( UIHTML, FlexLiItemsWrapContentWidth ) { Engine::destroySingleton(); } + +UTEST( UIHTML, ImagePercentageWidthRespectsParentMaxWidth ) { + auto win = Engine::instance()->createWindow( + WindowSettings( 1024, 768, "img pct width respects parent max-width", WindowStyle::Default, + WindowBackend::Default, 32, {}, 1, false, true ), + ContextSettings( false, 0, 0, GLv_default, true, false ) ); + + UISceneNode* sceneNode = init_test_inline_block(); + sceneNode->setURI( "file://" + Sys::getProcessPath() + "assets/html/" ); + + std::string html; + FileSystem::fileGet( "assets/html/image_width.html", html ); + sceneNode->loadLayoutFromString( HTMLFormatter::HTMLtoXML( html ) ); + + win->getInput()->update(); + SceneManager::instance()->update(); + sceneNode->updateDirtyLayouts(); + + auto articles = sceneNode->getRoot()->findAllByTag( "article" ); + ASSERT_GT( articles.size(), (size_t)0 ); + auto* articleWidget = articles[0]->asType(); + ASSERT_TRUE( articleWidget != nullptr ); + + auto images = sceneNode->getRoot()->findAllByTag( "img" ); + ASSERT_GT( images.size(), (size_t)0 ); + auto* imgWidget = images[0]->asType(); + ASSERT_TRUE( imgWidget != nullptr ); + + EXPECT_GT( articleWidget->getPixelsSize().getWidth(), 0.f ); + EXPECT_GT( articleWidget->getPixelsSize().getHeight(), 0.f ); + EXPECT_LE( articleWidget->getPixelsSize().getWidth(), 474.f ); + + EXPECT_GT( imgWidget->getPixelsSize().getWidth(), 0.f ); + EXPECT_GT( imgWidget->getPixelsSize().getHeight(), 0.f ); + EXPECT_LE( imgWidget->getPixelsSize().getWidth(), articleWidget->getPixelsSize().getWidth() ); + + auto anchors = sceneNode->getRoot()->findAllByTag( "a" ); + ASSERT_GT( anchors.size(), (size_t)0 ); + auto* anchorWidget = anchors[0]->asType(); + ASSERT_TRUE( anchorWidget != nullptr ); + EXPECT_GT( anchorWidget->getPixelsSize().getWidth(), 0.f ); + EXPECT_GT( anchorWidget->getPixelsSize().getHeight(), 0.f ); + + Engine::destroySingleton(); +} + +UTEST( UIHTML, ImageCSSWidthOverridesHTMLWidthAttribute ) { + auto win = Engine::instance()->createWindow( + WindowSettings( 1024, 768, "img css width overrides html width attr", WindowStyle::Default, + WindowBackend::Default, 32, {}, 1, false, true ), + ContextSettings( false, 0, 0, GLv_default, true, false ) ); + + UISceneNode* sceneNode = init_test_inline_block(); + sceneNode->setURI( "file://" + Sys::getProcessPath() + "assets/html/" ); + + std::string html; + FileSystem::fileGet( "assets/html/image_width_2.html", html ); + sceneNode->loadLayoutFromString( HTMLFormatter::HTMLtoXML( html ) ); + + win->getInput()->update(); + SceneManager::instance()->update(); + sceneNode->updateDirtyLayouts(); + + auto images = sceneNode->getRoot()->findAllByTag( "img" ); + ASSERT_GT( images.size(), (size_t)0 ); + auto* imgWidget = images[0]->asType(); + ASSERT_TRUE( imgWidget != nullptr ); + + auto mains = sceneNode->getRoot()->findAllByTag( "main" ); + ASSERT_GT( mains.size(), (size_t)0 ); + auto* mainWidget = mains[0]->asType(); + ASSERT_TRUE( mainWidget != nullptr ); + + Float imgWidth = imgWidget->getPixelsSize().getWidth(); + Float imgHeight = imgWidget->getPixelsSize().getHeight(); + Float mainWidth = mainWidget->getPixelsSize().getWidth(); + + EXPECT_GT( imgWidth, 0.f ); + EXPECT_GT( imgHeight, 0.f ); + + // CSS width: 100% should override HTML width="1500" + // Image should be no wider than its container + EXPECT_LE( imgWidth, mainWidth ); + + // Image should NOT be 1500 (the HTML attribute value) + EXPECT_LT( imgWidth, 1500.f ); + + Engine::destroySingleton(); +} + +UTEST( UIHTML, ImageMaxWidthConstrainsWebpWithHeightAuto ) { + auto win = Engine::instance()->createWindow( + WindowSettings( 1024, 768, "img max-width constrains webp with height auto", + WindowStyle::Default, WindowBackend::Default, 32, {}, 1, false, true ), + ContextSettings( false, 0, 0, GLv_default, true, false ) ); + + UISceneNode* sceneNode = init_test_inline_block(); + sceneNode->setURI( "file://" + Sys::getProcessPath() + "assets/html/" ); + + std::string html; + FileSystem::fileGet( "assets/html/image_width_3.html", html ); + sceneNode->loadLayoutFromString( HTMLFormatter::HTMLtoXML( html ) ); + + win->getInput()->update(); + SceneManager::instance()->update(); + sceneNode->updateDirtyLayouts(); + + auto articles = sceneNode->getRoot()->findAllByTag( "article" ); + ASSERT_GT( articles.size(), (size_t)0 ); + auto* articleWidget = articles[0]->asType(); + ASSERT_TRUE( articleWidget != nullptr ); + + auto images = sceneNode->getRoot()->findAllByTag( "img" ); + ASSERT_GT( images.size(), (size_t)0 ); + auto* imgWidget = images[0]->asType(); + ASSERT_TRUE( imgWidget != nullptr ); + + EXPECT_GT( articleWidget->getPixelsSize().getWidth(), 0.f ); + EXPECT_GT( articleWidget->getPixelsSize().getHeight(), 0.f ); + EXPECT_LE( articleWidget->getPixelsSize().getWidth(), 1140.f ); + + Float imgWidth = imgWidget->getPixelsSize().getWidth(); + Float imgHeight = imgWidget->getPixelsSize().getHeight(); + + EXPECT_GT( imgWidth, 0.f ); + EXPECT_GT( imgHeight, 0.f ); + EXPECT_LE( imgWidth, articleWidget->getPixelsSize().getWidth() ); + + // max-width: 100% should prevent the image from using the HTML width="2560" + EXPECT_LT( imgWidth, 2560.f ); + + // height should be proportional to width (aspect ratio: 1436/2560) + Float expectedRatio = 1436.f / 2560.f; + Float actualRatio = imgHeight / imgWidth; + EXPECT_GT( actualRatio, expectedRatio * 0.9f ); + EXPECT_LT( actualRatio, expectedRatio * 1.1f ); + + Engine::destroySingleton(); +}