浏览代码

Fix clipping of overflowing inline content. See #116.

Michael Ragazzon 5 年之前
父节点
当前提交
241824e986

+ 55 - 51
Source/Core/LayoutBlockBox.cpp

@@ -197,84 +197,88 @@ LayoutBlockBox::CloseResult LayoutBlockBox::Close()
 
 		box.SetContent(content_area);
 	}
+	
+	visible_outer_width = 0;
+	RMLUI_ASSERTMSG(!(context == INLINE && element), "The following assumes inline contexts do not represent a particular element.");
 
 	// Set the computed box on the element.
-	if (element != nullptr)
+	if (context == BLOCK && element)
 	{
-		if (context == BLOCK)
-		{
-			// 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(0, 0);
+		// 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(0, 0);
 
-			for (size_t i = 0; i < block_boxes.size(); i++)
-			{
-				// TODO: Only if the containing block is not an ancestor of us (ie. we are the containing block?).
-				content_box.x = Math::Max(content_box.x, block_boxes[i]->visible_outer_width);
-			}
+		for (size_t i = 0; i < block_boxes.size(); i++)
+		{
+			// TODO: Only if the containing block is not an ancestor of us (ie. we are the containing block?).
+			content_box.x = Math::Max(content_box.x, block_boxes[i]->visible_outer_width);
+		}
 
-			// Check how big our floated area is.
-			Vector2f space_box = space->GetDimensions();
-			content_box.x = Math::Max(content_box.x, space_box.x);
+		// Check how big our floated area is.
+		Vector2f space_box = space->GetDimensions();
+		content_box.x = Math::Max(content_box.x, space_box.x);
 
-			// If our content is larger than our window, we can enable the horizontal scrollbar if
-			// we're set to auto-scrollbars. If we're set to always use scrollbars, then the horiontal
-			// scrollbar will already have been enabled in the constructor.
-			if (content_box.x > box.GetSize().x)
+		// If our content is larger than our window, we can enable the horizontal scrollbar if
+		// we're set to auto-scrollbars. If we're set to always use scrollbars, then the horiontal
+		// scrollbar will already have been enabled in the constructor.
+		if (content_box.x > box.GetSize().x)
+		{
+			if (overflow_x_property == Style::Overflow::Auto)
 			{
-				if (overflow_x_property == Style::Overflow::Auto)
-				{
-					element->GetElementScroll()->EnableScrollbar(ElementScroll::HORIZONTAL, box.GetSize(Box::PADDING).x);
+				element->GetElementScroll()->EnableScrollbar(ElementScroll::HORIZONTAL, box.GetSize(Box::PADDING).x);
 
-					if (!CatchVerticalOverflow())
-						return LAYOUT_SELF;
-				}
+				if (!CatchVerticalOverflow())
+					return LAYOUT_SELF;
 			}
+		}
 
-			content_box.x += (box.GetEdge(Box::PADDING, Box::LEFT) + box.GetEdge(Box::PADDING, Box::RIGHT));
+		content_box.x += (box.GetEdge(Box::PADDING, Box::LEFT) + box.GetEdge(Box::PADDING, Box::RIGHT));
 
-			content_box.y = box_cursor;
-			content_box.y = Math::Max(content_box.y, space_box.y);
-			if (!CatchVerticalOverflow(content_box.y))
-				return LAYOUT_SELF;
+		content_box.y = box_cursor;
+		content_box.y = Math::Max(content_box.y, space_box.y);
+		if (!CatchVerticalOverflow(content_box.y))
+			return LAYOUT_SELF;
 
-			content_box.y += (box.GetEdge(Box::PADDING, Box::TOP) + box.GetEdge(Box::PADDING, Box::BOTTOM));
+		content_box.y += (box.GetEdge(Box::PADDING, Box::TOP) + box.GetEdge(Box::PADDING, Box::BOTTOM));
 
-			element->SetBox(box);
-			element->SetContentBox(space->GetOffset(), content_box);
+		element->SetBox(box);
+		element->SetContentBox(space->GetOffset(), content_box);
 
-			const float margin_width = GetBox().GetSize(Box::MARGIN).x;
-
-			// Set the visible outer width so that ancestors can catch any overflow produced by us. That is, hiding it or providing a scrolling mechanism.
-			// If we catch our own overflow here, then just use the normal margin box as that will effectively remove the overflow from our ancestor's perspective.
-			if (overflow_x_property != Style::Overflow::Visible)
-				visible_outer_width = margin_width;
-			else
-				visible_outer_width = Math::Max(margin_width, space->GetOffset().x + content_box.x + box.GetEdge(Box::MARGIN, Box::LEFT) + box.GetEdge(Box::MARGIN, Box::RIGHT));
+		const float margin_width = box.GetSize(Box::MARGIN).x;
 
+		// Set the visible outer width so that ancestors can catch any overflow produced by us. That is, hiding it or providing a scrolling mechanism.
+		// If we catch our own overflow here, then just use the normal margin box as that will effectively remove the overflow from our ancestor's perspective.
+		if (overflow_x_property != Style::Overflow::Visible)
+			visible_outer_width = margin_width;
+		else
+			visible_outer_width = Math::Max(margin_width, space->GetOffset().x + content_box.x + box.GetEdge(Box::MARGIN, Box::LEFT) + box.GetEdge(Box::MARGIN, Box::RIGHT));
 
-			// Format any scrollbars which were enabled on this element.
-			element->GetElementScroll()->FormatScrollbars();
+		// Format any scrollbars which were enabled on this element.
+		element->GetElementScroll()->FormatScrollbars();
+	}
+	else if (context == INLINE)
+	{
+		// Find the largest line in this layout block
+		for (size_t i = 0; i < line_boxes.size(); i++)
+		{
+			LayoutLineBox* line_box = line_boxes[i].get();
+			visible_outer_width = Math::Max(visible_outer_width, line_box->GetBoxCursor());
 		}
-		else
-			element->SetBox(box);
 	}
 
 	// Increment the parent's cursor.
 	if (parent != nullptr)
 	{
-		// If this close fails, it means this block box has caused our parent block box to generate an automatic
-		// vertical scrollbar.
+		// If this close fails, it means this block box has caused our parent block box to generate an automatic vertical scrollbar.
 		if (!parent->CloseBlockBox(this))
 			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 &&
-		element != nullptr)
+	if (context == BLOCK)
 	{
-		if (element->GetPosition() != Style::Position::Static)
+		if (!element || element->GetPosition() != Style::Position::Static)
 			CloseAbsoluteElements();
 	}
 
@@ -311,10 +315,10 @@ LayoutInlineBox* LayoutBlockBox::CloseLineBox(LayoutLineBox* child, UniquePtr<La
 	// Add a new line box.
 	line_boxes.push_back(MakeUnique<LayoutLineBox>(this));
 
-	if (overflow_chain != nullptr)
+	if (overflow_chain)
 		line_boxes.back()->AddChainedBox(overflow_chain);
 
-	if (overflow != nullptr)
+	if (overflow)
 		return line_boxes.back()->AddBox(std::move(overflow));
 
 	return nullptr;

+ 3 - 2
Source/Core/LayoutBlockBox.h

@@ -107,8 +107,6 @@ public:
 	/// rendering in a block-context.
 	/// @param element[in] The element to be positioned absolutely within this block box.
 	void AddAbsoluteElement(Element* element);
-	/// Formats, sizes, and positions all absolute elements in this block.
-	void CloseAbsoluteElements();
 
 	/// Returns the offset from the top-left corner of this box's offset element the next child box will be
 	/// positioned at.
@@ -169,6 +167,9 @@ private:
 		Vector2f position;
 	};
 
+	/// Formats, sizes, and positions all absolute elements in this block.
+	void CloseAbsoluteElements();
+
 	// Closes our last block box, if it is an open inline block box.
 	CloseResult CloseInlineBlockBox();
 

+ 1 - 0
Source/Core/LayoutDetails.h

@@ -77,6 +77,7 @@ public:
 	/// @return The dimensions of the content area, using the latest fixed dimensions for width and height in the hierarchy.
 	static Vector2f GetContainingBlock(const LayoutBlockBox* containing_box);
 
+	/// Formats the element and returns the width of its contents.
 	static float GetShrinkToFitWidth(Element* element, Vector2f containing_block);
 
 	/// Builds the block-specific width and horizontal margins of a Box.

+ 0 - 1
Source/Core/LayoutEngine.cpp

@@ -74,7 +74,6 @@ bool LayoutEngine::FormatElement(Element* element, Vector2f containing_block)
 	}
 
 	block_context_box->Close();
-	block_context_box->CloseAbsoluteElements();
 
 	element->OnLayout();
 

+ 8 - 0
Tests/Data/VisualTests/overflow_hidden.rml

@@ -59,5 +59,13 @@
 		<div class="absolute red">Should not be visible</div>
 	</div>
 </div>
+<div class="overflow">
+	<span>
+		LONG_WOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOORD&nbsp;FAIL
+	</span>
+	<div>
+		LONG_WOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOORD&nbsp;FAIL
+	</div>
+</div>
 </body>
 </rml>

+ 8 - 0
Tests/Data/VisualTests/reference/overflow_hidden-ref.rml

@@ -48,5 +48,13 @@
 	LONG_WOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOORD&nbsp;FAIL
 	<div class="absolute red">Should not be visible</div>
 </div>
+<div class="overflow">
+	<span>
+		LONG_WOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOORD&nbsp;FAIL
+	</span>
+	<div>
+		LONG_WOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOORD&nbsp;FAIL
+	</div>
+</div>
 </body>
 </rml>