Browse Source

Use shrink-to-fit width for floats and absolutetely positioned elements with auto width.

Michael Ragazzon 5 years ago
parent
commit
63a3a1b3dd

+ 14 - 4
Source/Core/LayoutBlockBox.cpp

@@ -211,7 +211,7 @@ LayoutBlockBox::CloseResult LayoutBlockBox::Close()
 		{
 			// Calculate the dimensions of the box's *internal* content; this is the tightest-fitting box around all of the
 			// internal elements, plus this element's padding.
-			Vector2f content_box = Vector2f(0, 0);
+			Vector2f content_box(0, 0);
 
 			for (size_t i = 0; i < block_boxes.size(); i++)
 			{
@@ -484,9 +484,20 @@ void LayoutBlockBox::CloseAbsoluteElements()
 			Vector2f absolute_position = absolute_elements[i].position;
 			absolute_position -= position - offset_root->GetPosition();
 
+			// See CSS 2.1 spec 10.3.7
+			const ComputedValues& computed = absolute_element->GetComputedValues();
+			bool shrink_to_fit = (computed.width.type == Style::Width::Auto && (computed.left.type == Style::Width::Auto || computed.right.type == Style::Width::Auto));
+
+			// Don't shrink replaced elements.
+			if (shrink_to_fit)
+			{
+				Vector2f unused_intrinsic_dimensions;
+				shrink_to_fit = !absolute_element->GetIntrinsicDimensions(unused_intrinsic_dimensions);
+			}
+
 			// Lay out the element.
 			LayoutEngine layout_engine;
-			layout_engine.FormatElement(absolute_element, containing_block);
+			layout_engine.FormatElement(absolute_element, containing_block, shrink_to_fit);
 
 			// Now that the element's box has been built, we can offset the position we determined was appropriate for
 			// it by the element's margin. This is necessary because the coordinate system for the box begins at the
@@ -583,8 +594,7 @@ float LayoutBlockBox::InternalContentWidth() const
 			}
 		}
 
-		content_width += (box.GetEdge(Box::PADDING, Box::LEFT) + box.GetEdge(Box::PADDING, Box::RIGHT));
-		content_width += (box.GetEdge(Box::MARGIN, Box::LEFT) + box.GetEdge(Box::MARGIN, Box::RIGHT));
+		content_width += box.GetCumulativeEdge(Box::PADDING, Box::LEFT) + box.GetCumulativeEdge(Box::PADDING, Box::RIGHT);
 	}
 	else
 	{

+ 26 - 11
Source/Core/LayoutEngine.cpp

@@ -63,7 +63,7 @@ LayoutEngine::~LayoutEngine()
 }
 
 // Formats the contents for a root-level element (usually a document or floating element).
-bool LayoutEngine::FormatElement(Element* element, const Vector2f& containing_block, bool shrink_to_fit)
+bool LayoutEngine::FormatElement(Element* element, Vector2f containing_block, bool shrink_to_fit)
 {
 #ifdef RMLUI_ENABLE_PROFILING
 	RMLUI_ZoneScopedC(0xB22222);
@@ -85,13 +85,13 @@ bool LayoutEngine::FormatElement(Element* element, const Vector2f& containing_bl
 	if (shrink_to_fit)
 	{
 		// For inline blocks with 'auto' width, we want to shrink the box back to its inner content width, recreating the LayoutBlockBox.
-		float content_width = block_box->InternalContentWidth();
+		const float content_width = block_context_box->InternalContentWidth();
 
 		if (content_width < containing_block.x)
 		{
 			RMLUI_ZoneScopedNC("shrink_to_fit", 0xB27222);
 
-			Vector2f shrinked_block_size(content_width, containing_block.y);
+			const Vector2f shrinked_block_size(content_width, containing_block.y);
 			
 			delete block_box;
 			block_box = new LayoutBlockBox(this, nullptr, nullptr);
@@ -300,12 +300,20 @@ bool LayoutEngine::FormatElement(Element* element)
 	}
 
 	// If the element is floating, we remove it from the flow.
-	Style::Float float_property = element->GetFloat();
-	if (float_property != Style::Float::None)
+	if (computed.float_ != Style::Float::None)
 	{
 		// Format the element as a block element.
 		LayoutEngine layout_engine;
-		layout_engine.FormatElement(element, GetContainingBlock(block_context_box));
+		bool shrink_to_fit = (computed.width.type == Style::Width::Auto);
+		
+		// Don't shrink replaced elements.
+		if (shrink_to_fit)
+		{
+			Vector2f unused_intrinsic_dimensions;
+			shrink_to_fit = !element->GetIntrinsicDimensions(unused_intrinsic_dimensions);
+		}
+
+		layout_engine.FormatElement(element, GetContainingBlock(block_context_box), shrink_to_fit);
 
 		return block_context_box->AddFloatElement(element);
 	}
@@ -315,7 +323,7 @@ bool LayoutEngine::FormatElement(Element* element)
 	{
 		case Style::Display::Block:       return FormatElementBlock(element); break;
 		case Style::Display::Inline:      return FormatElementInline(element); break;
-		case Style::Display::InlineBlock: return FormatElementReplaced(element); break;
+		case Style::Display::InlineBlock: return FormatElementInlineBlock(element); break;
 		default: RMLUI_ERROR;
 	}
 
@@ -392,13 +400,12 @@ bool LayoutEngine::FormatElementInline(Element* element)
 	}
 
 	inline_box->Close();
-//	element->OnLayout();
 
 	return true;
 }
 
 // Positions an element as a sized inline element, formatting its internal hierarchy as a block element.
-bool LayoutEngine::FormatElementReplaced(Element* element)
+bool LayoutEngine::FormatElementInlineBlock(Element* element)
 {
 	RMLUI_ZoneScopedC(0x1F2F2F);
 
@@ -406,8 +413,16 @@ bool LayoutEngine::FormatElementReplaced(Element* element)
 	Vector2f containing_block_size = GetContainingBlock(block_context_box);
 
 	LayoutEngine layout_engine;
-	bool shrink_to_width = element->GetComputedValues().width.type == Style::Width::Auto;
-	layout_engine.FormatElement(element, containing_block_size, shrink_to_width);
+	bool shrink_to_fit = element->GetComputedValues().width.type == Style::Width::Auto;
+	
+	// Don't shrink replaced elements.
+	if (shrink_to_fit)
+	{
+		Vector2f unused_intrinsic_dimensions;
+		shrink_to_fit = !element->GetIntrinsicDimensions(unused_intrinsic_dimensions);
+	}
+
+	layout_engine.FormatElement(element, containing_block_size, shrink_to_fit);
 
 	block_context_box->AddInlineElement(element, element->GetBox())->Close();
 

+ 2 - 2
Source/Core/LayoutEngine.h

@@ -49,7 +49,7 @@ public:
 	/// Formats the contents for a root-level element (usually a document, floating or replaced element).
 	/// @param element[in] The element to lay out.
 	/// @param containing_block[in] The size of the containing block.
-	bool FormatElement(Element* element, const Vector2f& containing_block, bool shrink_to_fit = false);
+	bool FormatElement(Element* element, Vector2f containing_block, bool shrink_to_fit = false);
 
 	/// Generates the box for an element.
 	/// @param[out] box The box to be built.
@@ -95,7 +95,7 @@ private:
 	bool FormatElementInline(Element* element);
 	/// Positions an element as a sized inline element, formatting its internal hierarchy as a block element.
 	/// @param[in] element The replaced element.
-	bool FormatElementReplaced(Element* element);
+	bool FormatElementInlineBlock(Element* element);
 	/// Executes any special formatting for special elements.
 	/// @param[in] element The element to parse.
 	/// @return True if the element was parsed as a special element, false otherwise.

+ 3 - 0
Tests/Data/VisualTests/inline_block.rml

@@ -16,6 +16,9 @@
 			display: inline-block;
 			color: #33c;
 		}
+		.iblock p {
+			text-align: right;
+		}
 	</style>
 </head>
 

+ 6 - 0
Tests/Data/VisualTests/shrink_to_fit.rml

@@ -28,6 +28,9 @@
 		.iblock {
 			display: inline-block;
 		}
+		.right {
+			text-align: right;
+		}
 	</style>
 </head>
 
@@ -48,5 +51,8 @@
 <div>
 	<div class="iblock">BOX</div>
 </div>
+<div>
+	<div class="iblock right">BOX</div>
+</div>
 </body>
 </rml>