diff --git a/include/eepp/ui/uirichtext.hpp b/include/eepp/ui/uirichtext.hpp index 8f8758000..05071a27e 100644 --- a/include/eepp/ui/uirichtext.hpp +++ b/include/eepp/ui/uirichtext.hpp @@ -257,9 +257,9 @@ class EE_API UIHTMLBody : public UIRichText { UIHTMLBody( const std::string& tag = "body" ); Float getLocalMinHeight() const; - void setDocumentContentMinHeight( const Float& height ); - void updateDocumentMinHeight(); - void updateDocumentContentMinHeightFromChildren(); + bool setDocumentContentMinHeight( const Float& height ); + bool updateDocumentMinHeight(); + bool updateDocumentContentMinHeightFromChildren(); virtual Uint32 onMessage( const NodeMessage* Msg ); }; diff --git a/src/eepp/ui/uirichtext.cpp b/src/eepp/ui/uirichtext.cpp index 296519c9d..a2e413116 100644 --- a/src/eepp/ui/uirichtext.cpp +++ b/src/eepp/ui/uirichtext.cpp @@ -296,27 +296,33 @@ Float UIHTMLBody::getLocalMinHeight() const { return convertLengthAsDp( mMinHeightLocal, parentHeight ); } -void UIHTMLBody::setDocumentContentMinHeight( const Float& height ) { +bool UIHTMLBody::setDocumentContentMinHeight( const Float& height ) { if ( mDocumentContentMinHeight == height ) - return; + return false; mDocumentContentMinHeight = height; - updateDocumentMinHeight(); + return updateDocumentMinHeight(); } -void UIHTMLBody::updateDocumentMinHeight() { +bool UIHTMLBody::updateDocumentMinHeight() { const Float oldMinHeight = getCurMinSize().getHeight(); Float minHeight = std::max( { getLocalMinHeight(), mDocumentViewportMinHeight, mDocumentContentMinHeight } ); setMinHeight( minHeight ); + bool minHeightChanged = minHeight != oldMinHeight; + bool sizeForced = false; if ( minHeight < oldMinHeight && - getPixelsSize().getHeight() > PixelDensity::dpToPx( minHeight ) ) + getPixelsSize().getHeight() > PixelDensity::dpToPx( minHeight ) ) { // Lowering min-height does not shrink the current box by itself. Reapply size through // min/max fitting so the body can settle at the new floor. setPixelsSize( { getPixelsSize().getWidth(), 0 } ); + sizeForced = true; + } + + return minHeightChanged || sizeForced; } -void UIHTMLBody::updateDocumentContentMinHeightFromChildren() { +bool UIHTMLBody::updateDocumentContentMinHeightFromChildren() { Float maxH = 0; Node* child = mChild; @@ -336,7 +342,7 @@ void UIHTMLBody::updateDocumentContentMinHeightFromChildren() { child = child->getNextNode(); } - setDocumentContentMinHeight( maxH > 0 ? std::trunc( PixelDensity::pxToDp( maxH ) ) : 0 ); + return setDocumentContentMinHeight( maxH > 0 ? std::trunc( PixelDensity::pxToDp( maxH ) ) : 0 ); } Uint32 UIHTMLBody::onMessage( const NodeMessage* Msg ) { @@ -345,10 +351,10 @@ Uint32 UIHTMLBody::onMessage( const NodeMessage* Msg ) { if ( Msg->getMsg() == NodeMessage::LayoutAttributeChange && Msg->getSender() != this && !mSettingBodyHeight ) { mSettingBodyHeight = true; - updateDocumentContentMinHeightFromChildren(); + bool documentMinHeightChanged = updateDocumentContentMinHeightFromChildren(); mSettingBodyHeight = false; - if ( getParent() && getParent()->isType( UI_TYPE_HTML_HTML ) ) + if ( documentMinHeightChanged && getParent() && getParent()->isType( UI_TYPE_HTML_HTML ) ) getParent()->asType()->setLayoutDirty( LayoutInvalidation::Document ); } diff --git a/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/gemini.cpp b/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/gemini.cpp new file mode 100644 index 000000000..19b6baaf6 --- /dev/null +++ b/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/gemini.cpp @@ -0,0 +1,91 @@ +#include +#include + +namespace EE { namespace UI { namespace Doc { namespace Language { + +SyntaxDefinition& addGemini() { + + return SyntaxDefinitionManager::instance() + ->add( + + { "Gemini", + { "%.gmi$" }, + { + { { "include", "#headings" }, "normal", "", SyntaxPatternMatchType::LuaPattern }, + { { "include", "#links" }, "normal", "", SyntaxPatternMatchType::LuaPattern }, + { { "include", "#quote" }, "normal", "", SyntaxPatternMatchType::LuaPattern }, + { { "include", "#raw" }, "normal", "", SyntaxPatternMatchType::LuaPattern }, + { { "include", "#unorderedLists" }, + "normal", + "", + SyntaxPatternMatchType::LuaPattern }, + + }, + { + + }, + "", + {} + + } ) + .addRepositories( { + + { "unorderedLists", + { + { { "^(\\*)[ \t]+.+\n" }, + { "normal", "operator" }, + {}, + "", + SyntaxPatternMatchType::RegEx }, + + } }, + { "raw", + { + { { "^```.*\n", "^```.*\n" }, + { "normal" }, + {}, + "", + SyntaxPatternMatchType::RegEx }, + + } }, + { "quote", + { + { { "^(>).*$" }, + { "string", "operator" }, + {}, + "", + SyntaxPatternMatchType::RegEx }, + + } }, + { "links", + { + { { "^=>[ \t]+([^ \t]+)(?:[ \t]+(.*))?" }, + { "normal", "link", "string" }, + {}, + "", + SyntaxPatternMatchType::RegEx }, + + } }, + { "headings", + { + { { "^(#)(?:[^#].*)?\n" }, + { "keyword", "operator" }, + {}, + "", + SyntaxPatternMatchType::RegEx }, + { { "^(##)(?:[^#].*)?\n" }, + { "keyword", "operator" }, + {}, + "", + SyntaxPatternMatchType::RegEx }, + { { "^(###)(?:[^#].*)?\n" }, + { "keyword", "operator" }, + {}, + "", + SyntaxPatternMatchType::RegEx }, + + } }, + } ); +} + +}}}} // namespace EE::UI::Doc::Language diff --git a/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/gemini.hpp b/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/gemini.hpp new file mode 100644 index 000000000..ded1aeeea --- /dev/null +++ b/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/gemini.hpp @@ -0,0 +1,11 @@ +#ifndef EE_UI_DOC_Gemini +#define EE_UI_DOC_Gemini +#include + +namespace EE { namespace UI { namespace Doc { namespace Language { + +extern SyntaxDefinition& addGemini(); + +}}}} // namespace EE::UI::Doc::Language + +#endif diff --git a/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languagessyntaxhighlighting.cpp b/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languagessyntaxhighlighting.cpp index 293f2f6a6..61cfb8b12 100644 --- a/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languagessyntaxhighlighting.cpp +++ b/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languagessyntaxhighlighting.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -359,6 +360,9 @@ static void preDefinitionLangsChunk1( SyntaxDefinitionManager* sdm ) { { "%.gd$" }, } ); + sdm->addPreDefinition( + { "Gemini", []() -> SyntaxDefinition& { return addGemini(); }, { "%.gmi$" } } ); + sdm->addPreDefinition( { "Gleam", []() -> SyntaxDefinition& { return addGleam(); }, { "%.gleam$" } } ); diff --git a/src/tests/unit_tests/uihtml_tests.cpp b/src/tests/unit_tests/uihtml_tests.cpp index ea9edb0ae..05d556574 100644 --- a/src/tests/unit_tests/uihtml_tests.cpp +++ b/src/tests/unit_tests/uihtml_tests.cpp @@ -4223,6 +4223,60 @@ UTEST( UIHTML, BodyDocumentContentMinHeightCanShrink ) { Engine::destroySingleton(); } +UTEST( UIHTML, BodyNoOpContentHeightChangeDoesNotDirtyHtml ) { + auto win = Engine::instance()->createWindow( + WindowSettings( 800, 600, "body no-op content height change", WindowStyle::Default, + WindowBackend::Default, 32, {}, 1, false, true ), + ContextSettings( false, 0, 0, GLv_default, true, false ) ); + + UISceneNode* sceneNode = init_test_inline_block(); + + UIWebView* webView = UIWebView::New(); + webView->setParent( sceneNode->getRoot() ); + webView->setPixelsSize( win->getWidth(), win->getHeight() ); + webView->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed ); + + std::string html = R"html( + + + +
+ + + )html"; + + sceneNode->setURI( "file://body-no-op-content-height-change.html" ); + sceneNode->loadLayoutFromString( HTMLFormatter::HTMLtoXML( html ), + webView->getDocumentContainer(), + String::hash( "body-no-op-content-height-change" ) ); + webView->refreshDocumentLayout(); + + win->getInput()->update(); + SceneManager::instance()->update(); + sceneNode->updateDirtyLayouts(); + win->getInput()->update(); + SceneManager::instance()->update(); + sceneNode->updateDirtyLayouts(); + + auto* htmlNode = sceneNode->getRoot()->findByType( UI_TYPE_HTML_HTML )->asType(); + auto* body = sceneNode->getRoot()->findByType( UI_TYPE_HTML_BODY )->asType(); + auto* spacer = sceneNode->getRoot()->find( "spacer" )->asType(); + ASSERT_TRUE( htmlNode != nullptr ); + ASSERT_TRUE( body != nullptr ); + ASSERT_TRUE( spacer != nullptr ); + ASSERT_GT( body->getPixelsSize().getHeight(), 850.f ); + ASSERT_FALSE( htmlNode->isLayoutDirty() ); + + spacer->setPixelsSize( + { spacer->getPixelsSize().getWidth() + 25.f, spacer->getPixelsSize().getHeight() } ); + EXPECT_FALSE( htmlNode->isLayoutDirty() ); + win->getInput()->update(); + SceneManager::instance()->update(); + sceneNode->updateDirtyLayouts(); + + Engine::destroySingleton(); +} + UTEST( UIHTML, DeferredCSSKeepsTableHeightStableAfterViewportResize ) { std::shared_ptr threadPool( ThreadPool::createShared( eemax( 4, Sys::getCPUCount() ) ) );