diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h index cf8ea096beb922..0e527708d8b34d 100644 --- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h +++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h @@ -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" @@ -38,6 +39,9 @@ struct CORE_EXPORT NGInlineItemResult { // NGLayoutResult for atomic inline items. RefPtr layout_result; + // NGBoxStrut for atomic inline items. + NGBoxStrut margins; + NGInlineItemResult(); NGInlineItemResult(unsigned index, unsigned start, unsigned end); }; diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc index 7df3b61d08fdf5..8264b3dba5bded 100644 --- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc +++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc @@ -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 break_token) { @@ -239,14 +248,17 @@ 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'. @@ -254,21 +266,22 @@ bool NGInlineLayoutAlgorithm::PlaceItems( box->AccumulateUsedFonts(item, item_result.start_offset, item_result.end_offset, baseline_type_); } + RefPtr 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 @@ -285,18 +298,7 @@ bool NGInlineLayoutAlgorithm::PlaceItems( continue; } - RefPtr 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()) { @@ -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(), @@ -341,13 +346,16 @@ 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 @@ -355,16 +363,8 @@ LayoutUnit NGInlineLayoutAlgorithm::PlaceAtomicInline( 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()); @@ -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 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() { diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h index c6f1db23d1499c..7e9e601c788089 100644 --- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h +++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h @@ -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); - 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(); diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc index f690f02b41d387..b87dc9aa1d93a9 100644 --- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc +++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc @@ -100,10 +100,17 @@ 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; @@ -111,15 +118,8 @@ LayoutObject* NGInlineNode::CollectInlines(LayoutObject* start, } 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; diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc index 7cadf42c80ba54..81aef02e4ac8ef 100644 --- a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc +++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc @@ -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" @@ -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.