diff --git a/src/eepp/graphics/richtext.cpp b/src/eepp/graphics/richtext.cpp index f64668522..8893bef7b 100644 --- a/src/eepp/graphics/richtext.cpp +++ b/src/eepp/graphics/richtext.cpp @@ -61,8 +61,7 @@ static Float getBaselineAlignedOffset( const RichText::RenderParagraph& line, co case RichText::BaselineAlignment::TextBottom: return baseline + getParentDescent( parentFontStyle ) - size.getHeight(); case RichText::BaselineAlignment::Middle: - return getParentAscent( parentFontStyle ) + getFontXHeight( parentFontStyle ) * 0.5f - - size.getHeight() * 0.5f; + return baseline + getFontXHeight( parentFontStyle ) * 0.5f - size.getHeight() * 0.5f; case RichText::BaselineAlignment::Top: return 0.f; case RichText::BaselineAlignment::Bottom: @@ -830,8 +829,12 @@ class RichTextInlineLayouter { Float baseline = span.baseline; RichText::BaselineAlignValue baselineAlign = effectiveInlineBaselineAlign( inlineItems, span.inlinePath, span.baselineAlign ); - Float offsetY = getBaselineAlignedOffset( - line, span.size, baseline, span.size.getHeight(), baselineAlign, defaultStyle ); + Float offsetY = baselineAlign.type == RichText::BaselineAlignment::Middle && + baseline > 0.f && baseline < span.size.getHeight() + ? line.maxAscent - baseline + : getBaselineAlignedOffset( line, span.size, baseline, + span.size.getHeight(), + baselineAlign, defaultStyle ); if ( preserveFloatPositions && isFloat ) { span.position.y = 0; continue; diff --git a/src/tests/unit_tests/richtext_tests.cpp b/src/tests/unit_tests/richtext_tests.cpp index 78f2a5015..10c4d236f 100644 --- a/src/tests/unit_tests/richtext_tests.cpp +++ b/src/tests/unit_tests/richtext_tests.cpp @@ -252,7 +252,41 @@ UTEST( RichText, VerticalAlignAtomicBoxes ) { RichText::InlineClear::None, 10.f, middleAlign ); middleRt.getSize(); ASSERT_EQ( middleRt.getLines().front().spans.size(), (size_t)2 ); - EXPECT_GT( middleRt.getLines().front().spans[1].position.y, baselineY ); + EXPECT_NEAR( middleRt.getLines().front().spans[1].position.y, baselineY, 0.001f ); + + RichText mixedRt; + mixedRt.getFontStyleConfig().Font = font; + mixedRt.getFontStyleConfig().CharacterSize = 20; + mixedRt.addSpan( "Large", nullptr, 30 ); + mixedRt.addCustomSize( Sizef( 10, 10 ), RichText::InlineFloat::None, + RichText::InlineClear::None, 5.f, middleAlign ); + mixedRt.getSize(); + ASSERT_EQ( mixedRt.getLines().front().spans.size(), (size_t)2 ); + const auto& mixedLine = mixedRt.getLines().front(); + Float expectedMiddleY = mixedLine.maxAscent - 5.f; + EXPECT_NEAR( mixedLine.spans[1].position.y, expectedMiddleY, 0.001f ); + + RichText nestedRt; + nestedRt.getFontStyleConfig().Font = font; + nestedRt.getFontStyleConfig().CharacterSize = 16; + FontStyleConfig smallStyle = nestedRt.getFontStyleConfig(); + smallStyle.CharacterSize = 10; + nestedRt.addSpan( "Title ", nullptr, 16 ); + nestedRt.pushInlineBox( Rectf::Zero, Rectf::Zero, 0, {}, Color::Transparent, 0, + Color::Transparent, 0, {} ); + nestedRt.addInlineText( "(", smallStyle, Rectf::Zero, Rectf::Zero, 0, {} ); + nestedRt.addCustomSize( Sizef( 36, 14 ), RichText::InlineFloat::None, + RichText::InlineClear::None, font->getAscent( 10 ), middleAlign ); + nestedRt.addInlineText( ")", smallStyle, Rectf::Zero, Rectf::Zero, 0, {} ); + nestedRt.popInlineBox(); + nestedRt.getSize(); + ASSERT_EQ( nestedRt.getLines().front().spans.size(), (size_t)4 ); + const auto& nestedOpenParen = nestedRt.getLines().front().spans[1]; + const auto& nestedAtomic = nestedRt.getLines().front().spans[2]; + ASSERT_TRUE( nestedOpenParen.text != nullptr ); + EXPECT_STRINGEQ( nestedOpenParen.text->getString(), "(" ); + EXPECT_EQ( nestedAtomic.type, RichText::RenderSpan::Type::AtomicBox ); + EXPECT_NEAR( nestedAtomic.position.y, nestedOpenParen.position.y, 0.5f ); RichText::BaselineAlignValue lengthAlign; lengthAlign.type = RichText::BaselineAlignment::Length;