Skip to content

Commit

Permalink
Fix clipping of overflowing inline content. See #116.
Browse files Browse the repository at this point in the history
  • Loading branch information
mikke89 committed Aug 10, 2020
1 parent e20d1af commit 241824e
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 54 deletions.
106 changes: 55 additions & 51 deletions Source/Core/LayoutBlockBox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down Expand Up @@ -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;
Expand Down
5 changes: 3 additions & 2 deletions Source/Core/LayoutBlockBox.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,6 @@ class LayoutBlockBox
/// 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.
Expand Down Expand Up @@ -169,6 +167,9 @@ class LayoutBlockBox
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();

Expand Down
1 change: 1 addition & 0 deletions Source/Core/LayoutDetails.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class LayoutDetails
/// @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.
Expand Down
1 change: 0 additions & 1 deletion Source/Core/LayoutEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ bool LayoutEngine::FormatElement(Element* element, Vector2f containing_block)
}

block_context_box->Close();
block_context_box->CloseAbsoluteElements();

element->OnLayout();

Expand Down
8 changes: 8 additions & 0 deletions Tests/Data/VisualTests/overflow_hidden.rml
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 8 additions & 0 deletions Tests/Data/VisualTests/reference/overflow_hidden-ref.rml
Original file line number Diff line number Diff line change
Expand Up @@ -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>

0 comments on commit 241824e

Please sign in to comment.