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.
This commit is contained in:
Martín Lucas Golini
2026-07-30 13:47:28 -03:00
parent 9fc385307a
commit 0485dc0d14
4 changed files with 65 additions and 8 deletions
+3 -1
View File
@@ -107,7 +107,9 @@ void UISvg::rasterizeSvg( const std::string& svgXml, const Sizef& targetSize ) {
return; return;
SpritePtr sprite = Sprite::New(); 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 { runOnMainThread( [this, sprite = std::move( sprite )]() mutable {
if ( sprite ) if ( sprite )
+1
View File
@@ -124,6 +124,7 @@ input[type="submit"],
input[type="button"], input[type="button"],
input[type="reset"] { input[type="reset"] {
display: inline-block; display: inline-block;
box-sizing: border-box;
border-width: 1dp; border-width: 1dp;
border-color: #767676; border-color: #767676;
background-color: #f0f0f0; background-color: #f0f0f0;
+37 -2
View File
@@ -2,6 +2,7 @@
#include <eepp/graphics/fontfamily.hpp> #include <eepp/graphics/fontfamily.hpp>
#include <eepp/graphics/fonttruetype.hpp> #include <eepp/graphics/fonttruetype.hpp>
#include <eepp/graphics/pixeldensity.hpp>
#include <eepp/scene/scenemanager.hpp> #include <eepp/scene/scenemanager.hpp>
#include <eepp/system/filesystem.hpp> #include <eepp/system/filesystem.hpp>
#include <eepp/system/sys.hpp> #include <eepp/system/sys.hpp>
@@ -263,15 +264,49 @@ UTEST( UISvg, percentageHeightResolvesAfterContainingBlockLayout ) {
ASSERT_TRUE( svgWidget != nullptr ); ASSERT_TRUE( svgWidget != nullptr );
EXPECT_EQ( svgWidget->getLayoutHeightPolicy(), SizePolicy::Fixed ); EXPECT_EQ( svgWidget->getLayoutHeightPolicy(), SizePolicy::Fixed );
EXPECT_GT( svgWidget->getPixelsSize().getHeight(), 0.f ); 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" ) ); button->setStyleSheetProperty( StyleSheetProperty( "height", "50px" ) );
sceneNode->updateDirtyLayouts(); sceneNode->updateDirtyLayouts();
EXPECT_NEAR( svgWidget->getPixelsSize().getHeight(), 50.f, 1.f ); EXPECT_NEAR( svgWidget->getPixelsSize().getHeight(), 43.f, 1.f );
destroyScene( sceneNode ); destroyScene( sceneNode );
} }
UTEST( UISvg, percentageSizeUsesPhysicalContainingBlockAtPixelDensity2 ) {
auto sceneNode = createScene();
ASSERT_TRUE( sceneNode != nullptr );
PixelDensity::setPixelDensity( 2.f );
std::string html = R"html(<!doctype html>
<html>
<body>
<div id="box" style="box-sizing:border-box;width:64px;height:34.5px;padding:2px 6px 3px">
<svg id="icon" viewBox="0 0 26 26" style="width:100%;height:100%">
<circle cx="13" cy="13" r="10"/>
</svg>
</div>
</body>
</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<UISvg>();
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 ) { UTEST( UISvg, svgWithMemoryAsset ) {
auto sceneNode = createScene(); auto sceneNode = createScene();
ASSERT_TRUE( sceneNode != nullptr ); ASSERT_TRUE( sceneNode != nullptr );
+24 -5
View File
@@ -615,8 +615,9 @@ UTEST( UIHTMLFloat, floatedListItemsShrinkToFitBlockAnchors ) {
Engine::destroySingleton(); Engine::destroySingleton();
} }
UTEST( UIHTMLFloat, ss64BlockAnchorsFillButtons ) { UTEST( UIHTMLFloat, ss64BlockAnchorsAndSvgAtPixelDensity2 ) {
init_float_test(); init_float_test();
PixelDensity::setPixelDensity( 2.f );
UISceneNode* sceneNode = SceneManager::instance()->getUISceneNode(); UISceneNode* sceneNode = SceneManager::instance()->getUISceneNode();
std::string html; std::string html;
ASSERT_TRUE( FileSystem::fileGet( "assets/html/ss64.html", html ) ); ASSERT_TRUE( FileSystem::fileGet( "assets/html/ss64.html", html ) );
@@ -629,16 +630,34 @@ UTEST( UIHTMLFloat, ss64BlockAnchorsFillButtons ) {
ASSERT_EQ( anchors.size(), buttons.size() ); ASSERT_EQ( anchors.size(), buttons.size() );
for ( size_t i = 0; i < buttons.size(); ++i ) { for ( size_t i = 0; i < buttons.size(); ++i ) {
auto* anchor = anchors[i]->asType<UIRichText>(); auto* anchor = anchors[i]->asType<UIRichText>();
EXPECT_NEAR( anchor->getLineHeightPx(), 40.f, 1.f ); EXPECT_NEAR( anchor->getLineHeightPx(), 80.f, 1.f );
EXPECT_NEAR( anchor->getPixelsSize().getHeight(), 40.f, 1.f ); EXPECT_NEAR( anchor->getPixelsSize().getHeight(), 80.f, 1.f );
EXPECT_NEAR( anchor->getPixelsSize().getHeight() + 2.f, EXPECT_NEAR( anchor->getPixelsSize().getHeight() + 4.f,
buttons[i]->getPixelsSize().getHeight(), 1.f ); buttons[i]->getPixelsSize().getHeight(), 1.f );
} }
auto* svg = sceneNode->getRoot()->querySelector( "#sherlock svg" )->asType<UISvg>(); auto* svg = sceneNode->getRoot()->querySelector( "#sherlock svg" )->asType<UISvg>();
auto* input = sceneNode->getRoot()->querySelector( "#qu" );
auto* searchButton = sceneNode->getRoot()->querySelector( "#sherlock" );
ASSERT_TRUE( input != nullptr );
ASSERT_TRUE( searchButton != nullptr );
ASSERT_TRUE( svg != 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_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(); Engine::destroySingleton();
PixelDensity::setPixelDensity( 1.f );
} }
UTEST( UIHTMLFloat, autoHorizontalMarginsCenterBlockInsideFloat ) { UTEST( UIHTMLFloat, autoHorizontalMarginsCenterBlockInsideFloat ) {