Browse Source

Add baseline offset for inline-block elements.

Michael Ragazzon 5 years ago
parent
commit
7c57bd3a80

+ 5 - 0
Include/RmlUi/Core/Element.h

@@ -55,6 +55,7 @@ class ElementDefinition;
 class ElementDocument;
 class ElementScroll;
 class ElementStyle;
+class LayoutBlockBox;
 class PropertiesIteratorView;
 class FontFaceHandleDefault;
 class PropertyDictionary;
@@ -639,6 +640,7 @@ private:
 
 	void DirtyOffset();
 	void UpdateOffset();
+	void SetBaseline(float baseline);
 
 	void BuildLocalStackingContext();
 	void BuildStackingContext(ElementList* stacking_context);
@@ -715,6 +717,8 @@ private:
 	// Defines what box area represents the element's client area; this is usually padding, but may be content.
 	Box::Area client_area;
 
+	float baseline;
+
 	// True if the element is visible and active.
 	bool visible;
 
@@ -751,6 +755,7 @@ private:
 	friend class Context;
 	friend class ElementStyle;
 	friend class LayoutEngine;
+	friend class LayoutBlockBox;
 	friend class LayoutInlineBox;
 	friend class ElementScroll;
 };

+ 8 - 1
Source/Core/Element.cpp

@@ -130,6 +130,8 @@ transform_state(), dirty_transform(false), dirty_perspective(false), dirty_anima
 
 	client_area = Box::PADDING;
 
+	baseline = 0.0f;
+
 	num_non_dom_children = 0;
 
 	visible = true;
@@ -542,7 +544,7 @@ int Element::GetNumBoxes()
 // Returns the baseline of the element, in pixels offset from the bottom of the element's content area.
 float Element::GetBaseline() const
 {
-	return 0;
+	return baseline;
 }
 
 // Gets the intrinsic dimensions of this element, if it is of a type that has an inherent size.
@@ -2165,6 +2167,11 @@ void Element::UpdateOffset()
 	}
 }
 
+void Element::SetBaseline(float in_baseline)
+{
+	baseline = in_baseline;
+}
+
 void Element::BuildLocalStackingContext()
 {
 	stacking_context_dirty = false;

+ 40 - 4
Source/Core/LayoutBlockBox.cpp

@@ -274,12 +274,48 @@ LayoutBlockBox::CloseResult LayoutBlockBox::Close()
 			return LAYOUT_PARENT;
 	}
 
-	// If we represent a positioned element, then we can now (as we've been sized) act as the containing block for all
-	// the absolutely-positioned elements of our descendants.
-	if (context == BLOCK)
+	if (context == BLOCK && element)
 	{
-		if (!element || element->GetPosition() != Style::Position::Static)
+		// If we represent a positioned element, then we can now (as we've been sized) act as the containing block for all
+		// the absolutely-positioned elements of our descendants.
+		if (element->GetPosition() != Style::Position::Static)
+		{
 			CloseAbsoluteElements();
+		}
+
+		// Set the baseline for inline-block elements to the baseline of the last line of the element.
+		// This is a special rule for inline-blocks (see CSS 2.1 §10.8.1).
+		if (element->GetDisplay() == Style::Display::InlineBlock)
+		{
+			bool found_baseline = false;
+			float baseline = 0;
+
+			for (int i = (int)block_boxes.size() - 1; i >= 0; i--)
+			{
+				if (block_boxes[i]->context == INLINE)
+				{
+					const LineBoxList& line_boxes = block_boxes[i]->line_boxes;
+					for (int j = (int)line_boxes.size() - 1; j >= 0; j--)
+					{
+						found_baseline = line_boxes[j]->GetBaselineOfLastLine(baseline);
+						if (found_baseline)
+							break;
+					}
+					if (found_baseline)
+						break;
+				}
+			}
+
+			if (found_baseline)
+			{
+				if (baseline < 0 && overflow_x_property != Style::Overflow::Visible || overflow_x_property != Style::Overflow::Visible)
+				{
+					baseline = 0;
+				}
+
+				element->SetBaseline(baseline);
+			}
+		}
 	}
 
 	return OK;

+ 1 - 2
Source/Core/LayoutInlineBox.cpp

@@ -47,8 +47,7 @@ LayoutInlineBox::LayoutInlineBox(Element* _element, const Box& _box) : position(
 
 	width = 0;
 
-	// If this box has intrinsic dimensions, then we set our height to the total height of the element; otherwise, it
-	// is zero height.
+	// If this box has intrinsic dimensions, then we set our height to the total height of the element; otherwise, it is zero height.
 	if (box.GetSize().y > 0)
 	{
 		height = box.GetSize(Box::MARGIN).y;

+ 8 - 0
Source/Core/LayoutLineBox.cpp

@@ -369,6 +369,14 @@ float LayoutLineBox::GetBoxCursor() const
 	return box_cursor; 
 }
 
+bool LayoutLineBox::GetBaselineOfLastLine(float& baseline) const
+{
+	if (inline_boxes.empty())
+		return false;
+	baseline = inline_boxes.back()->GetBaseline();
+	return true;
+}
+
 void* LayoutLineBox::operator new(size_t size)
 {
 	return LayoutEngine::AllocateLayoutChunk(size);

+ 2 - 0
Source/Core/LayoutLineBox.h

@@ -90,6 +90,8 @@ public:
 
 	float GetBoxCursor() const;
 
+	bool GetBaselineOfLastLine(float& baseline) const;
+
 	void* operator new(size_t size);
 	void operator delete(void* chunk);
 

+ 7 - 2
Tests/Data/VisualTests/inline_block.rml

@@ -9,9 +9,14 @@
 			color: #444;
 		}
 		.float {
-			float: left;
 			color: #393;
 		}
+		.left {
+			float: left;
+		}
+		.right {
+			float: right;
+		}
 		.iblock {
 			display: inline-block;
 			color: #33c;
@@ -29,7 +34,7 @@
 <hr/>
 <div>Left filler text. <div class="iblock">An inline-block. <p>A paragraph</p> Filler text.</div> Right filler text.</div>
 <hr/>
-<div>Left filler text. <div class="iblock">An inline-block. <div class="float">A float</div> Filler text.</div> Right filler text.</div>
+<div>Left filler text. <div class="iblock">An inline-block. <div class="float right">Float right</div><div class="float left">Float left</div> Filler text.</div> Right filler text.</div>
 <hr/>
 <div class="iblock">Nesting inline-blocks: 
 	<div class="iblock">A<div class="iblock">B<div class="iblock">C</div></div></div>

+ 1 - 1
Tests/Data/style.rcss

@@ -1,4 +1,4 @@
-dl,dt,dd,ul,li,blockquote,address,h1,h2,h3,h4,h5,h6,p,pre,div {
+dl,dt,dd,ul,li,blockquote,address,h1,h2,h3,h4,h5,h6,p,pre,div,section {
 	display: block;
 }