mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-28 17:16:29 +03:00
Don't let <head> participate in layouting.
This commit is contained in:
@@ -128,6 +128,7 @@ enum UINodeType {
|
||||
UI_TYPE_DIFF_VIEW,
|
||||
UI_TYPE_BR,
|
||||
UI_TYPE_HTML_HTML,
|
||||
UI_TYPE_HTML_HEAD,
|
||||
UI_TYPE_HTML_BODY,
|
||||
UI_TYPE_HTML_LIST_ITEM,
|
||||
UI_TYPE_HTML_IMAGE,
|
||||
|
||||
@@ -11,7 +11,13 @@ class EE_API UIRichText : public UIHTMLWidget {
|
||||
public:
|
||||
enum class IntrinsicMode { None, Min, Max };
|
||||
|
||||
enum class WhiteSpaceCollapse { Collapse, Preserve, PreserveBreaks, PreserveSpaces, BreakSpaces };
|
||||
enum class WhiteSpaceCollapse {
|
||||
Collapse,
|
||||
Preserve,
|
||||
PreserveBreaks,
|
||||
PreserveSpaces,
|
||||
BreakSpaces
|
||||
};
|
||||
|
||||
static WhiteSpaceCollapse toWhiteSpaceCollapse( std::string val );
|
||||
|
||||
@@ -213,6 +219,16 @@ class EE_API UIHTMLBody : public UIRichText {
|
||||
UIHTMLBody( const std::string& tag = "body" );
|
||||
};
|
||||
|
||||
class EE_API UIHTMLHead : public UIWidget {
|
||||
public:
|
||||
static UIHTMLHead* New();
|
||||
virtual Uint32 getType() const override;
|
||||
bool isType( const Uint32& type ) const override;
|
||||
|
||||
protected:
|
||||
UIHTMLHead();
|
||||
};
|
||||
|
||||
class EE_API UILineBreak : public UIRichText {
|
||||
public:
|
||||
static UILineBreak* New( const std::string& tag );
|
||||
|
||||
@@ -211,6 +211,23 @@ void UIHTMLBody::updateLayout() {
|
||||
}
|
||||
}
|
||||
|
||||
UIHTMLHead* UIHTMLHead::New() {
|
||||
return eeNew( UIHTMLHead, () );
|
||||
}
|
||||
|
||||
UIHTMLHead::UIHTMLHead() : UIWidget() {
|
||||
mVisible = false;
|
||||
mEnabled = false;
|
||||
}
|
||||
|
||||
Uint32 UIHTMLHead::getType() const {
|
||||
return UI_TYPE_HTML_HEAD;
|
||||
}
|
||||
|
||||
bool UIHTMLHead::isType( const Uint32& type ) const {
|
||||
return UIHTMLHead::getType() == type ? true : UIWidget::isType( type );
|
||||
}
|
||||
|
||||
UIRichText* UIRichText::NewHtml() {
|
||||
auto* html = UIHTMLHtml::New( "html" );
|
||||
html->setClipType( ClipType::None );
|
||||
@@ -1028,6 +1045,10 @@ void UIRichText::rebuildRichText( UILayout* container, RichText& richText, Intri
|
||||
|
||||
UIWidget* widget = node->asType<UIWidget>();
|
||||
|
||||
// Skip <head> - it must not participate in layout
|
||||
if ( widget->isType( UI_TYPE_HTML_HEAD ) )
|
||||
return;
|
||||
|
||||
bool handled = false;
|
||||
|
||||
if ( widget->isType( UI_TYPE_HTML_WIDGET ) && widget->asType<UIHTMLWidget>()->isInline() ) {
|
||||
|
||||
@@ -236,7 +236,7 @@ void UIWidgetCreator::createBaseWidgetList() {
|
||||
};
|
||||
registeredWidget["aside"] = [] { return UIRichText::NewWithTag( "aside" ); };
|
||||
registeredWidget["html"] = UIRichText::NewHtml;
|
||||
registeredWidget["head"] = [] { return UIWidget::NewWithTag( "head" ); };
|
||||
registeredWidget["head"] = UIHTMLHead::New;
|
||||
registeredWidget["body"] = UIRichText::NewBody;
|
||||
registeredWidget["form"] = [] { return UIHTMLForm::New(); };
|
||||
registeredWidget["table"] = UIHTMLTable::New;
|
||||
|
||||
@@ -30,6 +30,7 @@ using namespace EE::Window;
|
||||
using namespace EE::Scene;
|
||||
using namespace EE::UI;
|
||||
using namespace EE::UI::CSS;
|
||||
using namespace EE::UI::Tools;
|
||||
|
||||
// Helper: create a basic scene for RichText tests
|
||||
static UI::UISceneNode* createRichTextScene() {
|
||||
@@ -879,8 +880,7 @@ UTEST( UITextNode_BlockLayouter, OverFindHitsAnchorWhenMatchingText ) {
|
||||
|
||||
if ( !anchor->getHitBoxes().empty() ) {
|
||||
const Rectf& firstHb = anchor->getHitBoxes()[0];
|
||||
Vector2f hitPos = anchor->convertToWorldSpace(
|
||||
{ firstHb.Left + 1, firstHb.Top + 1 } );
|
||||
Vector2f hitPos = anchor->convertToWorldSpace( { firstHb.Left + 1, firstHb.Top + 1 } );
|
||||
Node* hitNode = rt->overFind( hitPos );
|
||||
EXPECT_EQ( hitNode, anchor );
|
||||
}
|
||||
@@ -914,8 +914,7 @@ UTEST( UITextNode_BlockLayouter, NestedSpanOverFindHitsInnerSpan ) {
|
||||
|
||||
if ( !inner->getHitBoxes().empty() ) {
|
||||
const Rectf& firstHb = inner->getHitBoxes()[0];
|
||||
Vector2f hitPos = inner->convertToWorldSpace(
|
||||
{ firstHb.Left + 1, firstHb.Top + 1 } );
|
||||
Vector2f hitPos = inner->convertToWorldSpace( { firstHb.Left + 1, firstHb.Top + 1 } );
|
||||
Node* hitNode = rt->overFind( hitPos );
|
||||
EXPECT_TRUE( hitNode == inner || hitNode->inParentTreeOf( inner ) );
|
||||
}
|
||||
@@ -994,6 +993,49 @@ UTEST( UITextNode_EdgeCases, DirectChildOfRichText ) {
|
||||
// Suite: UITextNode_RegressionTests
|
||||
// ============================================================
|
||||
|
||||
UTEST( UITextNode_Regression, BackgroundPositioningBodyYWithLineHeight ) {
|
||||
auto sceneNode = createRichTextScene();
|
||||
ASSERT_TRUE( sceneNode != nullptr );
|
||||
|
||||
String xml = R"xml(
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<style>
|
||||
html {
|
||||
color: #555;
|
||||
line-height: 1.5;
|
||||
font-size: 16px;
|
||||
}
|
||||
body {
|
||||
padding: 0 10px 0 10px;
|
||||
margin: 0;
|
||||
border-top: 4px solid #b45f38;
|
||||
}
|
||||
</style>
|
||||
<body id="body">
|
||||
<header class="site-header">
|
||||
<nav class="site-nav">
|
||||
<a class="menu-link" href="/">Home</a>
|
||||
</nav>
|
||||
</header>
|
||||
</body>
|
||||
</html>
|
||||
)xml";
|
||||
|
||||
sceneNode->loadLayoutFromString( HTMLFormatter::HTMLtoXML( xml ) );
|
||||
sceneNode->update( Time::Zero );
|
||||
|
||||
auto* body = sceneNode->find<UIWidget>( "body" );
|
||||
ASSERT_TRUE( body != nullptr );
|
||||
|
||||
// Body must be at Y=0 - the <head> element should NOT participate in layout
|
||||
// and should NOT create an empty line with line-height applied.
|
||||
EXPECT_NEAR( body->getPixelsPosition().y, 0.f, 1.f );
|
||||
|
||||
destroyRichTextScene( sceneNode );
|
||||
}
|
||||
|
||||
UTEST( UITextNode_Regression, WhitespaceCollapseDoesNotCreateSpuriousNodes ) {
|
||||
auto sceneNode = createRichTextScene();
|
||||
ASSERT_TRUE( sceneNode != nullptr );
|
||||
|
||||
Reference in New Issue
Block a user