diff --git a/bin/unit_tests/assets/html/lobsters_simple.html b/bin/unit_tests/assets/html/lobsters_simple.html new file mode 100644 index 000000000..b7b17bfe9 --- /dev/null +++ b/bin/unit_tests/assets/html/lobsters_simple.html @@ -0,0 +1,468 @@ + + + + + + +
+ +
    +
  1. +
    +
    + 104 +
    +
    + + Redis and the Cost of Ambition + + + databases + + charlesleifer.com + +
    +
    + +
  2. +
+
diff --git a/include/eepp/ui/uitextspan.hpp b/include/eepp/ui/uitextspan.hpp index 9fea7da7d..0bc02f180 100644 --- a/include/eepp/ui/uitextspan.hpp +++ b/include/eepp/ui/uitextspan.hpp @@ -136,12 +136,17 @@ class EE_API UITextSpan : public UIRichText { void setHitBoxes( SpanHitBoxes&& hitBoxes ); + Int64 getLayoutCharCount() const { return mLayoutCharCount; } + + void setLayoutCharCount( Int64 count ) { mLayoutCharCount = count; } + virtual Node* overFind( const Vector2f& point ); protected: Uint32 mStyleState{ StyleStateNone }; String mText; SpanHitBoxes mHitBoxes; + Int64 mLayoutCharCount{ 0 }; explicit UITextSpan( const std::string& tag = "span" ); diff --git a/src/eepp/ui/blocklayouter.cpp b/src/eepp/ui/blocklayouter.cpp index 584e22e82..60c33f5dc 100644 --- a/src/eepp/ui/blocklayouter.cpp +++ b/src/eepp/ui/blocklayouter.cpp @@ -247,8 +247,9 @@ void BlockLayouter::positionRichTextChildren( Graphics::RichText* rt ) { Int64 startChar = curCharIdx; Int64 endChar = curCharIdx; - if ( !textSpan->getText().empty() ) { - endChar += textSpan->getText().length(); + Int64 layoutCount = textSpan->getLayoutCharCount(); + if ( layoutCount > 0 ) { + endChar += layoutCount; curCharIdx = endChar; } diff --git a/src/eepp/ui/uirichtext.cpp b/src/eepp/ui/uirichtext.cpp index 8bc079ad3..8ca72ba4c 100644 --- a/src/eepp/ui/uirichtext.cpp +++ b/src/eepp/ui/uirichtext.cpp @@ -953,6 +953,7 @@ void UIRichText::rebuildRichText( UILayout* container, RichText& richText, Intri if ( widget->isType( UI_TYPE_HTML_WIDGET ) && widget->asType()->isMergeable() ) { UITextSpan* span = widget->asType(); + span->setLayoutCharCount( 0 ); Rectf margin = span->getLayoutPixelsMargin(); Rectf padding = span->getPixelsPadding(); bool hasOwnText = !span->getText().empty() && NULL != span->getFontStyleConfig().Font; @@ -988,8 +989,11 @@ void UIRichText::rebuildRichText( UILayout* container, RichText& richText, Intri if ( !spanText.empty() ) { richText.addSpan( spanText, span->getFontStyleConfig(), margin, padding, spanLineHeight, span->isInlineBlock() ); + span->setLayoutCharCount( spanText.length() ); if ( shouldCollapse ) lastSpanEndsWithSpace = spanText.back() == ' '; + } else { + span->setLayoutCharCount( 0 ); } } else if ( margin.Left > 0 || margin.Top > 0 || padding.Left > 0 || padding.Top > 0 ) { Rectf leftOnly( margin.Left, margin.Top, 0, 0 ); diff --git a/src/tests/unit_tests/uihtml_tests.cpp b/src/tests/unit_tests/uihtml_tests.cpp index 1672556bd..3bd2a1fb4 100644 --- a/src/tests/unit_tests/uihtml_tests.cpp +++ b/src/tests/unit_tests/uihtml_tests.cpp @@ -1550,3 +1550,47 @@ UTEST( UIBackground, InlineBlockImageFixedSize ) { Engine::destroySingleton(); } + +UTEST( UIHTML, AnchorsSizing ) { + auto win = Engine::instance()->createWindow( + WindowSettings( 1024, 653, "anchors sizing", WindowStyle::Default, WindowBackend::Default, + 32, {}, 1, false, true ), + ContextSettings( false, 0, 0, GLv_default, true, false ) ); + FileSystem::changeWorkingDirectory( Sys::getProcessPath() ); + + UI::UISceneNode* sceneNode = init_test_inline_block(); + + sceneNode->setURI( "file://" + Sys::getProcessPath() + "assets/html/" ); + + std::string html; + FileSystem::fileGet( "assets/html/lobsters_simple.html", html ); + sceneNode->loadLayoutFromString( HTMLFormatter::HTMLtoXML( html ) ); + win->setClearColor( Color::White ); + + win->getInput()->update(); + SceneManager::instance()->update(); + + win->clear(); + SceneManager::instance()->draw(); + win->display(); + + auto anchors = sceneNode->getRoot()->findAllByTag( "a" ); + + EXPECT_GT( anchors.size(), (size_t)0 ); + + for ( auto anchor : anchors ) { + auto a = anchor->asType(); + if ( a->getDisplay() == CSSDisplay::None ) + continue; + EXPECT_GT( a->getPixelsSize().getHeight(), 0 ); + if ( !a->getText().empty() && a->getFontStyleConfig().Font ) { + String text = a->getText(); + text.trim(); + if ( !text.empty() ) + EXPECT_GE( a->getPixelsSize().getWidth(), + Text::getTextWidth( text, a->getFontStyleConfig() ) ); + } + } + + Engine::destroySingleton(); +}