Skip to content

Commit

Permalink
[LayoutNG] Implement inline margins for atomic inline boxes
Browse files Browse the repository at this point in the history
This patch implements inline margins for atomic inline boxes. Inline
margins for non-replaced inline boxes is not included and will be in
following patches.

Also changes not to generate OpenTag/CloseTag NGInlineItem for atomic
inline boxes. Atomic inlines use their margin boxes for inline layout
purposes, while non-replaced inline boxes has different characteristics.
Not generating OpenTag/CloseTag helps single code to handle both cases.

BUG=636993,723135

Review-Url: https://codereview.chromium.org/2883213003
Cr-Commit-Position: refs/heads/master@{#472478}
  • Loading branch information
kojiishi authored and Commit bot committed May 17, 2017
1 parent e21aa45 commit 8876859
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#ifndef NGInlineItemResult_h
#define NGInlineItemResult_h

#include "core/layout/ng/geometry/ng_box_strut.h"
#include "core/layout/ng/ng_layout_result.h"
#include "platform/LayoutUnit.h"
#include "platform/fonts/shaping/ShapeResult.h"
Expand Down Expand Up @@ -38,6 +39,9 @@ struct CORE_EXPORT NGInlineItemResult {
// NGLayoutResult for atomic inline items.
RefPtr<NGLayoutResult> layout_result;

// NGBoxStrut for atomic inline items.
NGBoxStrut margins;

NGInlineItemResult();
NGInlineItemResult(unsigned index, unsigned start, unsigned end);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,15 @@ LayoutUnit NGInlineLayoutAlgorithm::AvailableWidth() const {
return current_opportunity_.InlineSize();
}

// The offset of 'line-left' side.
// https://drafts.csswg.org/css-writing-modes/#line-left
LayoutUnit NGInlineLayoutAlgorithm::LogicalLeftOffset() const {
// TODO(kojii): We need to convert 'line start' to 'line left'. They're
// different in RTL. Maybe there are more where start and left are misused.
return current_opportunity_.InlineStartOffset() -
ConstraintSpace().BfcOffset().inline_offset;
}

bool NGInlineLayoutAlgorithm::CreateLine(
NGInlineItemResults* item_results,
RefPtr<NGInlineBreakToken> break_token) {
Expand Down Expand Up @@ -239,36 +248,40 @@ bool NGInlineLayoutAlgorithm::PlaceItems(
NGTextFragmentBuilder text_builder(Node());
NGInlineBoxState* box =
box_states_.OnBeginPlaceItems(&LineStyle(), baseline_type_);
LayoutUnit inline_size;

// Place items from line-left to line-right along with the baseline.
// Items are already bidi-reordered to the visual order.
LayoutUnit line_left_position = LogicalLeftOffset();
LayoutUnit position = line_left_position;

for (auto& item_result : *line_items) {
const NGInlineItem& item = items[item_result.item_index];
LayoutUnit line_top;
if (item.Type() == NGInlineItem::kText) {
DCHECK(item.GetLayoutObject()->IsText());
DCHECK(!box->text_metrics.IsEmpty());
line_top = box->text_top;
text_builder.SetSize(
{item_result.inline_size, box->text_metrics.LineHeight()});
// Take all used fonts into account if 'line-height: normal'.
if (box->include_used_fonts) {
box->AccumulateUsedFonts(item, item_result.start_offset,
item_result.end_offset, baseline_type_);
}
RefPtr<NGPhysicalTextFragment> text_fragment =
text_builder.ToTextFragment(item_result.item_index,
item_result.start_offset,
item_result.end_offset);
line_box.AddChild(std::move(text_fragment), {position, box->text_top});
} else if (item.Type() == NGInlineItem::kOpenTag) {
box = box_states_.OnOpenTag(item, &line_box, &text_builder);
// Compute text metrics for all inline boxes since even empty inlines
// influence the line height.
// https://drafts.csswg.org/css2/visudet.html#line-height
// TODO(kojii): Review if atomic inline level should have open/close.
if (!item.GetLayoutObject()->IsAtomicInlineLevel())
box->ComputeTextMetrics(*item.Style(), baseline_type_);
continue;
box->ComputeTextMetrics(*item.Style(), baseline_type_);
} else if (item.Type() == NGInlineItem::kCloseTag) {
box = box_states_.OnCloseTag(item, &line_box, box, baseline_type_);
continue;
} else if (item.Type() == NGInlineItem::kAtomicInline) {
line_top =
PlaceAtomicInline(item, &item_result, &line_box, box, &text_builder);
box = PlaceAtomicInline(item, &item_result, position, &line_box,
&text_builder);
} else if (item.Type() == NGInlineItem::kOutOfFlowPositioned) {
// TODO(layout-dev): Report the correct static position for the out of
// flow descendant. We can't do this here yet as it doesn't know the
Expand All @@ -285,18 +298,7 @@ bool NGInlineLayoutAlgorithm::PlaceItems(
continue;
}

RefPtr<NGPhysicalTextFragment> text_fragment = text_builder.ToTextFragment(
item_result.item_index, item_result.start_offset,
item_result.end_offset);

NGLogicalOffset opportunity_offset =
current_opportunity_.InlineStartBlockStartOffset() -
ContainerBfcOffset();
NGLogicalOffset line_offset = {
opportunity_offset.inline_offset + inline_size, line_top};

inline_size += item_result.inline_size;
line_box.AddChild(std::move(text_fragment), line_offset);
position += item_result.inline_size;
}

if (line_box.Children().IsEmpty()) {
Expand Down Expand Up @@ -329,6 +331,9 @@ bool NGInlineLayoutAlgorithm::PlaceItems(
// at 0. Move them to the final baseline position, and set the logical top of
// the line box to the line top.
line_box.MoveChildrenInBlockDirection(baseline);

DCHECK_EQ(line_left_position, LogicalLeftOffset());
LayoutUnit inline_size = position - line_left_position;
line_box.SetInlineSize(inline_size);
container_builder_.AddChild(
line_box.ToLineBoxFragment(),
Expand All @@ -341,30 +346,25 @@ bool NGInlineLayoutAlgorithm::PlaceItems(

// TODO(kojii): Currently, this function does not change item_result, but
// when NG paint is enabled, this will std::move() the LayoutResult.
LayoutUnit NGInlineLayoutAlgorithm::PlaceAtomicInline(
NGInlineBoxState* NGInlineLayoutAlgorithm::PlaceAtomicInline(
const NGInlineItem& item,
NGInlineItemResult* item_result,
LayoutUnit position,
NGLineBoxFragmentBuilder* line_box,
NGInlineBoxState* state,
NGTextFragmentBuilder* text_builder) {
DCHECK(item_result->layout_result);

NGInlineBoxState* box = box_states_.OnOpenTag(item, line_box, text_builder);

// For replaced elements, inline-block elements, and inline-table elements,
// the height is the height of their margin box.
// https://drafts.csswg.org/css2/visudet.html#line-height
NGBoxFragment fragment(
ConstraintSpace().WritingMode(),
ToNGPhysicalBoxFragment(
item_result->layout_result->PhysicalFragment().Get()));
DCHECK(item.Style());
NGBoxStrut margins = ComputeMargins(ConstraintSpace(), *item.Style(),
ConstraintSpace().WritingMode(),
item.Style()->Direction());
LayoutUnit block_size = fragment.BlockSize() + margins.BlockSum();

// TODO(kojii): Try to eliminate the wrapping text fragment and use the
// |fragment| directly. Currently |CopyFragmentDataToLayoutBlockFlow|
// requires a text fragment.
text_builder->SetSize({fragment.InlineSize(), block_size});
LayoutUnit block_size =
fragment.BlockSize() + item_result->margins.BlockSum();

// TODO(kojii): Add baseline position to NGPhysicalFragment.
LayoutBox* layout_box = ToLayoutBox(item.GetLayoutObject());
Expand All @@ -375,12 +375,22 @@ LayoutUnit NGInlineLayoutAlgorithm::PlaceAtomicInline(
baseline_type_, IsFirstLine(), line_direction_mode));

NGLineHeightMetrics metrics(baseline_offset, block_size - baseline_offset);
state->metrics.Unite(metrics);
box->metrics.Unite(metrics);

// TODO(kojii): Figure out what to do with OOF in NGLayoutResult.
// Floats are ok because atomic inlines are BFC?

return -(metrics.ascent - margins.block_start);
// TODO(kojii): Try to eliminate the wrapping text fragment and use the
// |fragment| directly. Currently |CopyFragmentDataToLayoutBlockFlow|
// requires a text fragment.
text_builder->SetSize({fragment.InlineSize(), block_size});
LayoutUnit line_top = item_result->margins.block_start - metrics.ascent;
RefPtr<NGPhysicalTextFragment> text_fragment = text_builder->ToTextFragment(
item_result->item_index, item_result->start_offset,
item_result->end_offset);
line_box->AddChild(std::move(text_fragment), {position, line_top});

return box_states_.OnCloseTag(item, line_box, box, baseline_type_);
}

void NGInlineLayoutAlgorithm::FindNextLayoutOpportunity() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,16 @@ class CORE_EXPORT NGInlineLayoutAlgorithm final
const ComputedStyle& FirstLineStyle() const;
const ComputedStyle& LineStyle() const;

LayoutUnit LogicalLeftOffset() const;

void BidiReorder(NGInlineItemResults*);

bool PlaceItems(NGInlineItemResults*, RefPtr<NGInlineBreakToken>);
LayoutUnit PlaceAtomicInline(const NGInlineItem&,
NGInlineItemResult*,
NGLineBoxFragmentBuilder*,
NGInlineBoxState*,
NGTextFragmentBuilder*);
NGInlineBoxState* PlaceAtomicInline(const NGInlineItem&,
NGInlineItemResult*,
LayoutUnit position,
NGLineBoxFragmentBuilder*,
NGTextFragmentBuilder*);

// Finds the next layout opportunity for the next text fragment.
void FindNextLayoutOpportunity();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,26 +100,26 @@ LayoutObject* NGInlineNode::CollectInlines(LayoutObject* start,
// NGInlineLayoutAlgorithm.
builder->Append(NGInlineItem::kFloating, kObjectReplacementCharacter,
nullptr, node);

} else if (node->IsOutOfFlowPositioned()) {
builder->Append(NGInlineItem::kOutOfFlowPositioned,
kObjectReplacementCharacter, nullptr, node);

} else if (node->IsAtomicInlineLevel()) {
// For atomic inlines add a unicode "object replacement character" to
// signal the presence of a non-text object to the unicode bidi algorithm.
builder->Append(NGInlineItem::kAtomicInline, kObjectReplacementCharacter,
node->Style(), node);

} else if (!node->IsInline()) {
// A block box found. End inline and transit to block layout.
return node;

} else {
builder->EnterInline(node);

// For atomic inlines add a unicode "object replacement character" to
// signal the presence of a non-text object to the unicode bidi algorithm.
if (node->IsAtomicInlineLevel()) {
builder->Append(NGInlineItem::kAtomicInline,
kObjectReplacementCharacter, node->Style(), node);
}

// Otherwise traverse to children if they exist.
else if (LayoutObject* child = node->SlowFirstChild()) {
// Traverse to children if they exist.
if (LayoutObject* child = node->SlowFirstChild()) {
node = child;
continue;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "core/layout/ng/ng_constraint_space.h"
#include "core/layout/ng/ng_fragment_builder.h"
#include "core/layout/ng/ng_layout_opportunity_iterator.h"
#include "core/layout/ng/ng_length_utils.h"
#include "core/style/ComputedStyle.h"
#include "platform/fonts/shaping/HarfBuzzShaper.h"
#include "platform/fonts/shaping/ShapingLineBreaker.h"
Expand Down Expand Up @@ -225,6 +226,11 @@ void NGLineBreaker::LayoutAtomicInline(const NGInlineItem& item,
ToNGPhysicalBoxFragment(
item_result->layout_result->PhysicalFragment().Get()))
.InlineSize();

item_result->margins =
ComputeMargins(*constraint_space_, style,
constraint_space_->WritingMode(), style.Direction());
item_result->inline_size += item_result->margins.InlineSum();
}

// Handles when the last item overflows.
Expand Down

0 comments on commit 8876859

Please sign in to comment.