Pārlūkot izejas kodu

Add 'vertical-align: center' value

Michael Ragazzon 2 gadi atpakaļ
vecāks
revīzija
48590d19ef

+ 1 - 1
Include/RmlUi/Core/StyleTypes.h

@@ -104,7 +104,7 @@ namespace Style {
 		{}
 	};
 	struct VerticalAlign {
-		enum Type : uint8_t { Baseline, Middle, Sub, Super, TextTop, TextBottom, Top, Bottom, Length } type;
+		enum Type : uint8_t { Baseline, Middle, Sub, Super, TextTop, TextBottom, Top, Center, Bottom, Length } type;
 		float value; // For length type
 		VerticalAlign(Type type = Baseline) : type(type), value(0) {}
 		VerticalAlign(float value) : type(Length), value(value) {}

+ 1 - 0
Source/Core/Layout/InlineLevelBox.cpp

@@ -104,6 +104,7 @@ void InlineLevelBox::SetHeightAndVerticalAlignment(float _height_above_baseline,
 		self_baseline_offset = 0.5f * (height_above_baseline - depth_below_baseline);
 		break;
 	case VerticalAlign::Top:
+	case VerticalAlign::Center:
 	case VerticalAlign::Bottom:
 		// These are relative to the line box and handled later.
 		break;

+ 16 - 2
Source/Core/Layout/LineBox.cpp

@@ -269,11 +269,24 @@ UniquePtr<LineBox> LineBox::DetermineVerticalPositioning(const InlineBoxRoot* ro
 				VerticallyAlignSubtree(subtree_root_index, fragment.children_end_index, fragment.max_ascent, fragment.max_descent);
 			}
 
+			const float subtree_height = fragment.max_ascent + fragment.max_descent;
+
 			// Increase the line box size to fit all line-relative aligned fragments.
 			switch (fragment.vertical_align)
 			{
-			case VerticalAlignType::Top: max_descent = Math::Max(max_descent, fragment.max_ascent + fragment.max_descent - max_ascent); break;
-			case VerticalAlignType::Bottom: max_ascent = Math::Max(max_ascent, fragment.max_ascent + fragment.max_descent - max_descent); break;
+			case VerticalAlignType::Top: max_descent = Math::Max(max_descent, subtree_height - max_ascent); break;
+			case VerticalAlignType::Bottom: max_ascent = Math::Max(max_ascent, subtree_height - max_descent); break;
+			case VerticalAlignType::Center:
+			{
+				// Distribute the subtree's height equally to the ascent and descent.
+				const float distribute_height = 0.5f * (subtree_height - (max_ascent + max_descent));
+				if (distribute_height > 0.f)
+				{
+					max_ascent += distribute_height;
+					max_descent += distribute_height;
+				}
+			}
+			break;
 			default: RMLUI_ERROR; break;
 			}
 		}
@@ -290,6 +303,7 @@ UniquePtr<LineBox> LineBox::DetermineVerticalPositioning(const InlineBoxRoot* ro
 		{
 		case VerticalAlignType::Top: fragment.position.y = fragment.max_ascent; break;
 		case VerticalAlignType::Bottom: fragment.position.y = out_height_of_line - fragment.max_descent; break;
+		case VerticalAlignType::Center: fragment.position.y = 0.5f * (fragment.max_ascent - fragment.max_descent + out_height_of_line); break;
 		default:
 		{
 			RMLUI_ASSERT(!IsAlignedSubtreeRoot(fragment));

+ 2 - 1
Source/Core/Layout/LineBox.h

@@ -155,7 +155,8 @@ private:
 	// Returns true if the fragment establishes an aligned subtree.
 	static bool IsAlignedSubtreeRoot(const Fragment& fragment)
 	{
-		return (fragment.vertical_align == VerticalAlignType::Top || fragment.vertical_align == VerticalAlignType::Bottom);
+		return (fragment.vertical_align == VerticalAlignType::Top || fragment.vertical_align == VerticalAlignType::Center ||
+			fragment.vertical_align == VerticalAlignType::Bottom);
 	}
 	// Returns the aligned subtree root for a given fragment, based on its ancestors.
 	FragmentIndex DetermineAlignedSubtreeRoot(FragmentIndex index) const

+ 1 - 1
Source/Core/StyleSheetSpecification.cpp

@@ -354,7 +354,7 @@ void StyleSheetSpecification::RegisterDefaultProperties()
 
 	RegisterProperty(PropertyId::LineHeight, "line-height", "1.2", true, true).AddParser("number_length_percent").SetRelativeTarget(RelativeTarget::FontSize);
 	RegisterProperty(PropertyId::VerticalAlign, "vertical-align", "baseline", false, true)
-		.AddParser("keyword", "baseline, middle, sub, super, text-top, text-bottom, top, bottom")
+		.AddParser("keyword", "baseline, middle, sub, super, text-top, text-bottom, top, center, bottom")
 		.AddParser("length_percent").SetRelativeTarget(RelativeTarget::LineHeight);
 
 	RegisterProperty(PropertyId::OverflowX, "overflow-x", "visible", false, true).AddParser("keyword", "visible, hidden, auto, scroll");

+ 21 - 5
Tests/Data/VisualTests/inline_formatting_06.rml

@@ -6,12 +6,19 @@
 	<meta name="Description" content="Line height with inline-blocks." />
 	<meta name="Assert" content="The baseline of an inline-block is the baseline of its last line box in the normal flow, unless it has either no in-flow line boxes or if its overflow property has a computed value other than visible, in which case the baseline is the bottom margin edge." />
 	<style>
-		p.value { color: #45e; margin: -0.5em 0 0.2em 1em; }
+		p.value {
+			position: absolute;
+			margin: 0.4em 0.6em;
+			top: 0;
+			right: 0;
+			color: #45e;
+		}
 		.wrapper {
 			background-color: #eee;
 			border: 3px #bbb;
 			padding: 8px;
-			margin-bottom: 1.5em;
+			position: relative;
+			margin-top: -0.3em;
 		}
 		.wrapper > div {
 			display: inline-block;
@@ -25,11 +32,12 @@
 		}
 		.scroll-container > div { overflow: auto; }
 		.offset-up > div { vertical-align: -12px; }
+		.vertical-center > div { vertical-align: center; }
 	</style>
 </head>
 
 <body>
-<p>Normally, the baseline of an inline-block is set to its last line, nicely aligning up with its neighboring text.</p>
+<p>Normally, the baseline of an inline-block is set to its last line, nicely aligning with its neighboring text.</p>
 <div class="wrapper">
 	X <div>Start Game</div><br/>
 	X <div>High Scores</div><br/>
@@ -37,16 +45,24 @@
 </div>
 
 <p>However, after making the inline-block a scroll container (such as by setting a non-visible overflow value), it is instead aligned to its bottom edge. Due to the line's text descent, there is additional spacing appearing below the box.</p>
-<p class="value">overflow: auto;</p>
 <div class="wrapper scroll-container">
+	<p class="value">overflow: auto;</p>
 	X <div>Start Game</div><br/>
 	X <div>High Scores</div><br/>
 	X <div>Options</div>
 </div>
 
 <p>We can manually adjust the vertical alignment to make sure we remove that additional space. However, it won't perfectly line up the baselines anymore.</p>
-<p class="value">overflow: auto;<br/>vertical-align: -12px</p>
 <div class="wrapper scroll-container offset-up">
+	<p class="value">overflow: auto;<br/>vertical-align: -12px;</p>
+	X <div>Start Game</div><br/>
+	X <div>High Scores</div><br/>
+	X <div>Options</div>
+</div>
+
+<p>Instead of manually adjusting the vertical alignment, we can use 'center' for perfect centering. Note that baselines will still not line up.</p>
+<div class="wrapper scroll-container vertical-center">
+	<p class="value">overflow: auto;<br/>vertical-align: center;</p>
 	X <div>Start Game</div><br/>
 	X <div>High Scores</div><br/>
 	X <div>Options</div>

+ 18 - 1
Tests/Data/VisualTests/inline_formatting_aligned_subtree.rml

@@ -3,7 +3,7 @@
     <title>Inline formatting - Aligned subtree</title>
     <link type="text/rcss" href="../style.rcss"/>
 	<link rel="help" href="https://drafts.csswg.org/css2/#aligned-subtree" />
-	<meta name="Description" content="Children of an inline element whose 'vertical-align' property is 'top' or 'bottom' is aligned relative to it." />
+	<meta name="Description" content="Children of an inline element whose 'vertical-align' property is 'top', 'center', or 'bottom', is aligned relative to it." />
 	<style>
 		body {
 			background: #ddd;
@@ -31,6 +31,7 @@
 		.small  { line-height: 1.2em; }
 		
 		.top     { vertical-align: top; }
+		.center  { vertical-align: center; }
 		.bottom  { vertical-align: bottom; }
 		.line-up { vertical-align: -100%; }
 		
@@ -89,6 +90,22 @@
 	</span>
 	<span class="tall block">F</span>
 </div>
+<div class="wrapper">
+	<span class="small bottom">
+		A
+		<span class="medium block center">
+			B
+			<span class="bottom yellow">
+				C
+				<span class="line-up">
+					D
+					<span class="center">E</span>
+				</span>
+			</span>
+		</span>
+	</span>
+	<span class="tall block">F</span>
+</div>
 <div class="wrapper split">
 	The following text <span>should wrap down to the<br/> next line</span> and produce borders on each line.
 </div>