From 0485dc0d1473e2363446577d28a45492b508c303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Thu, 30 Jul 2026 13:47:28 -0300 Subject: [PATCH] Fix HTML button sizing and HiDPI SVG rendering Use border-box sizing for HTML buttons to match browser user-agent styles and prevent padding from increasing explicitly declared button heights. Keep inline SVG textures rasterized at full physical resolution while assigning density-independent sprite destination sizes, avoiding double scaling on HiDPI displays. Add SS64 and pixel-density regressions for button alignment, percentage-sized SVG layout, and drawable dimensions. --- src/eepp/ui/uisvg.cpp | 4 ++- src/eepp/ui/uiwidgetcreator.cpp | 1 + src/tests/unit_tests/htmlsvg_tests.cpp | 39 +++++++++++++++++++-- src/tests/unit_tests/uihtml_float_tests.cpp | 29 ++++++++++++--- 4 files changed, 65 insertions(+), 8 deletions(-) diff --git a/src/eepp/ui/uisvg.cpp b/src/eepp/ui/uisvg.cpp index 201b34a5f..07e15dfd9 100644 --- a/src/eepp/ui/uisvg.cpp +++ b/src/eepp/ui/uisvg.cpp @@ -107,7 +107,9 @@ void UISvg::rasterizeSvg( const std::string& svgXml, const Sizef& targetSize ) { return; SpritePtr sprite = Sprite::New(); - sprite->createStatic( std::move( texture ) ); + // TextureRegion destination sizes are density-independent and get converted back to pixels by + // the drawable. The SVG texture is already rasterized at the widget's physical pixel size. + sprite->createStatic( std::move( texture ), PixelDensity::pxToDp( targetSize ) ); runOnMainThread( [this, sprite = std::move( sprite )]() mutable { if ( sprite ) diff --git a/src/eepp/ui/uiwidgetcreator.cpp b/src/eepp/ui/uiwidgetcreator.cpp index 693964022..191dc2490 100644 --- a/src/eepp/ui/uiwidgetcreator.cpp +++ b/src/eepp/ui/uiwidgetcreator.cpp @@ -124,6 +124,7 @@ input[type="submit"], input[type="button"], input[type="reset"] { display: inline-block; + box-sizing: border-box; border-width: 1dp; border-color: #767676; background-color: #f0f0f0; diff --git a/src/tests/unit_tests/htmlsvg_tests.cpp b/src/tests/unit_tests/htmlsvg_tests.cpp index a334db7bd..c42dbd5df 100644 --- a/src/tests/unit_tests/htmlsvg_tests.cpp +++ b/src/tests/unit_tests/htmlsvg_tests.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -263,15 +264,49 @@ UTEST( UISvg, percentageHeightResolvesAfterContainingBlockLayout ) { ASSERT_TRUE( svgWidget != nullptr ); EXPECT_EQ( svgWidget->getLayoutHeightPolicy(), SizePolicy::Fixed ); EXPECT_GT( svgWidget->getPixelsSize().getHeight(), 0.f ); - EXPECT_NEAR( svgWidget->getPixelsSize().getHeight(), 34.5f, 1.f ); + EXPECT_NEAR( button->getPixelsSize().getHeight(), 34.5f, 1.f ); + EXPECT_NEAR( svgWidget->getPixelsSize().getHeight(), 27.5f, 1.f ); button->setStyleSheetProperty( StyleSheetProperty( "height", "50px" ) ); sceneNode->updateDirtyLayouts(); - EXPECT_NEAR( svgWidget->getPixelsSize().getHeight(), 50.f, 1.f ); + EXPECT_NEAR( svgWidget->getPixelsSize().getHeight(), 43.f, 1.f ); destroyScene( sceneNode ); } +UTEST( UISvg, percentageSizeUsesPhysicalContainingBlockAtPixelDensity2 ) { + auto sceneNode = createScene(); + ASSERT_TRUE( sceneNode != nullptr ); + PixelDensity::setPixelDensity( 2.f ); + + std::string html = R"html( + + +
+ + + +
+ +)html"; + + auto rootWidget = sceneNode->loadLayoutFromString( HTMLFormatter::HTMLtoXML( html ) ); + ASSERT_TRUE( rootWidget != nullptr ); + sceneNode->updateDirtyLayouts(); + + auto* box = rootWidget->querySelector( "#box" ); + auto* svgWidget = rootWidget->querySelector( "#icon" )->asType(); + ASSERT_TRUE( box != nullptr ); + ASSERT_TRUE( svgWidget != nullptr ); + EXPECT_NEAR( box->getPixelsSize().getWidth(), 128.f, 1.f ); + EXPECT_NEAR( box->getPixelsSize().getHeight(), 69.f, 1.f ); + EXPECT_NEAR( svgWidget->getPixelsSize().getWidth(), 104.f, 1.f ); + EXPECT_NEAR( svgWidget->getPixelsSize().getHeight(), 59.f, 1.f ); + + destroyScene( sceneNode ); + PixelDensity::setPixelDensity( 1.f ); +} + UTEST( UISvg, svgWithMemoryAsset ) { auto sceneNode = createScene(); ASSERT_TRUE( sceneNode != nullptr ); diff --git a/src/tests/unit_tests/uihtml_float_tests.cpp b/src/tests/unit_tests/uihtml_float_tests.cpp index 43163fc62..fbb4b77af 100644 --- a/src/tests/unit_tests/uihtml_float_tests.cpp +++ b/src/tests/unit_tests/uihtml_float_tests.cpp @@ -615,8 +615,9 @@ UTEST( UIHTMLFloat, floatedListItemsShrinkToFitBlockAnchors ) { Engine::destroySingleton(); } -UTEST( UIHTMLFloat, ss64BlockAnchorsFillButtons ) { +UTEST( UIHTMLFloat, ss64BlockAnchorsAndSvgAtPixelDensity2 ) { init_float_test(); + PixelDensity::setPixelDensity( 2.f ); UISceneNode* sceneNode = SceneManager::instance()->getUISceneNode(); std::string html; ASSERT_TRUE( FileSystem::fileGet( "assets/html/ss64.html", html ) ); @@ -629,16 +630,34 @@ UTEST( UIHTMLFloat, ss64BlockAnchorsFillButtons ) { ASSERT_EQ( anchors.size(), buttons.size() ); for ( size_t i = 0; i < buttons.size(); ++i ) { auto* anchor = anchors[i]->asType(); - EXPECT_NEAR( anchor->getLineHeightPx(), 40.f, 1.f ); - EXPECT_NEAR( anchor->getPixelsSize().getHeight(), 40.f, 1.f ); - EXPECT_NEAR( anchor->getPixelsSize().getHeight() + 2.f, + EXPECT_NEAR( anchor->getLineHeightPx(), 80.f, 1.f ); + EXPECT_NEAR( anchor->getPixelsSize().getHeight(), 80.f, 1.f ); + EXPECT_NEAR( anchor->getPixelsSize().getHeight() + 4.f, buttons[i]->getPixelsSize().getHeight(), 1.f ); } auto* svg = sceneNode->getRoot()->querySelector( "#sherlock svg" )->asType(); + auto* input = sceneNode->getRoot()->querySelector( "#qu" ); + auto* searchButton = sceneNode->getRoot()->querySelector( "#sherlock" ); + ASSERT_TRUE( input != nullptr ); + ASSERT_TRUE( searchButton != nullptr ); ASSERT_TRUE( svg != nullptr ); + EXPECT_NEAR( input->getPixelsSize().getHeight(), 74.5f, 1.f ); + EXPECT_NEAR( searchButton->getPixelsSize().getHeight(), 69.f, 1.f ); + EXPECT_LE( searchButton->getPixelsPosition().y + searchButton->getPixelsSize().getHeight(), + input->getPixelsPosition().y + input->getPixelsSize().getHeight() ); EXPECT_EQ( svg->getLayoutHeightPolicy(), SizePolicy::Fixed ); - EXPECT_GT( svg->getPixelsSize().getHeight(), 0.f ); + EXPECT_NEAR( svg->getPixelsSize().getHeight(), 59.f, 1.f ); + for ( int i = 0; i < 500 && svg->getDrawable() == nullptr; ++i ) { + SceneManager::instance()->update(); + Sys::sleep( Milliseconds( 1 ) ); + } + ASSERT_TRUE( svg->getDrawable() != nullptr ); + EXPECT_NEAR( svg->getDrawable()->getPixelsSize().getWidth(), svg->getPixelsSize().getWidth(), + 1.f ); + EXPECT_NEAR( svg->getDrawable()->getPixelsSize().getHeight(), svg->getPixelsSize().getHeight(), + 1.f ); Engine::destroySingleton(); + PixelDensity::setPixelDensity( 1.f ); } UTEST( UIHTMLFloat, autoHorizontalMarginsCenterBlockInsideFloat ) {