Commit 00b2e0c7 authored by Ian Kilpatrick's avatar Ian Kilpatrick Committed by Commit Bot

[LayoutNG] Introduce NGLineLayoutOpportunity.

There should be no behaviour change in this patch. This introduces the
"line layout opportunity concept" which has:
 - A line size.
 - A float line size.

Bug: 635619
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_layout_tests_layout_ng
Change-Id: Ib8667a7c0909116da8e89cb2e20d9df66a2c401d
Reviewed-on: https://chromium-review.googlesource.com/1035617Reviewed-by: default avatarEmil A Eklund <eae@chromium.org>
Reviewed-by: default avatarMorten Stenshorne <mstensho@chromium.org>
Reviewed-by: default avatarKoji Ishii <kojii@chromium.org>
Commit-Queue: Ian Kilpatrick <ikilpatrick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#557614}
parent 47c575ab
......@@ -282,6 +282,8 @@ blink_core_sources("layout") {
"multi_column_fragmentainer_group.h",
"ng/exclusions/ng_exclusion_space.cc",
"ng/exclusions/ng_exclusion_space.h",
"ng/exclusions/ng_layout_opportunity.h",
"ng/exclusions/ng_line_layout_opportunity.h",
"ng/geometry/ng_bfc_offset.cc",
"ng/geometry/ng_bfc_offset.h",
"ng/geometry/ng_bfc_rect.cc",
......@@ -290,7 +292,6 @@ blink_core_sources("layout") {
"ng/geometry/ng_border_edges.h",
"ng/geometry/ng_box_strut.cc",
"ng/geometry/ng_box_strut.h",
"ng/geometry/ng_edge.h",
"ng/geometry/ng_logical_offset.cc",
"ng/geometry/ng_logical_offset.h",
"ng/geometry/ng_logical_rect.cc",
......
......@@ -10,6 +10,11 @@
namespace blink {
// This struct represents an 2D-area where a NGFragment can fit within the
// exclusion space. A layout opportunity is produced by the exclusion space by
// calling FindLayoutOpportunity, or AllLayoutOpportunities.
//
// Its coordinates are relative to the BFC.
struct CORE_EXPORT NGLayoutOpportunity {
NGLayoutOpportunity()
: rect(NGBfcOffset(LayoutUnit::Min(), LayoutUnit::Min()),
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_EXCLUSIONS_NG_LINE_LAYOUT_OPPORTUNITY_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_EXCLUSIONS_NG_LINE_LAYOUT_OPPORTUNITY_H_
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/layout_unit.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
namespace blink {
// This struct represents a 1D-area where a line can fit. It is only used for
// representing the inline size.
struct CORE_EXPORT NGLineLayoutOpportunity {
STACK_ALLOCATED();
NGLineLayoutOpportunity() {}
NGLineLayoutOpportunity(LayoutUnit inline_size)
: line_right_offset(inline_size), float_line_right_offset(inline_size) {}
NGLineLayoutOpportunity(LayoutUnit line_left_offset,
LayoutUnit line_right_offset,
LayoutUnit float_line_left_offset,
LayoutUnit float_line_right_offset,
LayoutUnit bfc_block_offset,
LayoutUnit line_block_size)
: line_left_offset(line_left_offset),
line_right_offset(line_right_offset),
float_line_left_offset(float_line_left_offset),
float_line_right_offset(float_line_right_offset),
bfc_block_offset(bfc_block_offset),
line_block_size(line_block_size) {}
// The available inline-size of the line, taking shapes into account. Both
// offsets are relative to the BFC coordinate system.
LayoutUnit line_left_offset;
LayoutUnit line_right_offset;
// The available inline-size of the line *for floats*. This is the same size
// as the layout opportunity which generated this object. Both offsets are
// relative to the BFC coordinate system.
LayoutUnit float_line_left_offset;
LayoutUnit float_line_right_offset;
LayoutUnit bfc_block_offset;
// The block-size this line layout opportunity was created with. Should
// *only* be used for re-querying for a new line layout opportunity with the
// same block-size.
LayoutUnit line_block_size;
LayoutUnit AvailableInlineSize() const {
DCHECK_GE(line_right_offset, line_left_offset);
return line_right_offset - line_left_offset;
}
LayoutUnit AvailableFloatInlineSize() const {
DCHECK_GE(float_line_right_offset, float_line_left_offset);
return float_line_right_offset - float_line_left_offset;
}
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_EXCLUSIONS_NG_LINE_LAYOUT_OPPORTUNITY_H_
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NGEdge_h
#define NGEdge_h
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/layout_unit.h"
namespace blink {
// Struct to represent a simple edge that has start and end.
struct CORE_EXPORT NGEdge {
LayoutUnit start;
LayoutUnit end;
};
} // namespace blink
#endif // NGEdge_h
......@@ -618,6 +618,11 @@ scoped_refptr<NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
exclusion_space =
std::make_unique<NGExclusionSpace>(*initial_exclusion_space);
NGLineLayoutOpportunity line_opportunity(
opportunity.rect.LineStartOffset(), opportunity.rect.LineEndOffset(),
opportunity.rect.LineStartOffset(), opportunity.rect.LineEndOffset(),
opportunity.rect.BlockStartOffset(), LayoutUnit());
NGLineInfo line_info;
NGLineBreaker line_breaker(
Node(), NGLineBreakerMode::kContent, constraint_space_,
......@@ -626,14 +631,14 @@ scoped_refptr<NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
// TODO(ikilpatrick): Does this always succeed when we aren't an empty
// inline?
if (!line_breaker.NextLine(opportunity, &line_info))
if (!line_breaker.NextLine(line_opportunity, &line_info))
break;
// If this fragment will be larger than the inline-size of the opportunity,
// *and* the opportunity is smaller than the available inline-size, and the
// container autowraps, continue to the next opportunity.
if (line_info.Width() > opportunity.rect.InlineSize() &&
opportunity.rect.InlineSize() !=
if (line_info.Width() > line_opportunity.AvailableInlineSize() &&
line_opportunity.AvailableInlineSize() !=
ConstraintSpace().AvailableSize().inline_size &&
Node().Style().AutoWrap())
continue;
......
......@@ -596,8 +596,7 @@ static LayoutUnit ComputeContentSize(NGInlineNode node,
scoped_refptr<NGInlineBreakToken> break_token;
NGLineInfo line_info;
NGExclusionSpace empty_exclusion_space;
NGLayoutOpportunity opportunity(NGBfcRect(
NGBfcOffset(), NGBfcOffset(available_inline_size, LayoutUnit::Max())));
NGLineLayoutOpportunity line_opportunity(available_inline_size);
LayoutUnit result;
LayoutUnit previous_floats_inline_size =
input.float_left_inline_size + input.float_right_inline_size;
......@@ -608,7 +607,7 @@ static LayoutUnit ComputeContentSize(NGInlineNode node,
&unpositioned_floats,
nullptr /* container_builder */,
&empty_exclusion_space, 0u, break_token.get());
if (!line_breaker.NextLine(opportunity, &line_info))
if (!line_breaker.NextLine(line_opportunity, &line_info))
break;
break_token = line_breaker.CreateBreakToken(line_info, nullptr);
......
......@@ -153,8 +153,9 @@ void NGLineBreaker::ComputeBaseDirection(const NGLineInfo& line_info) {
}
// Initialize internal states for the next line.
void NGLineBreaker::PrepareNextLine(const NGLayoutOpportunity& opportunity,
NGLineInfo* line_info) {
void NGLineBreaker::PrepareNextLine(
const NGLineLayoutOpportunity& line_opportunity,
NGLineInfo* line_info) {
NGInlineItemResults* item_results = &line_info->Results();
item_results->clear();
line_info->SetStartOffset(offset_);
......@@ -177,17 +178,12 @@ void NGLineBreaker::PrepareNextLine(const NGLayoutOpportunity& opportunity,
// regardless of 'text-indent'.
line_.position = line_info->TextIndent();
line_.opportunity = opportunity;
line_.line_left_bfc_offset = opportunity.rect.LineStartOffset();
line_.line_right_bfc_offset = opportunity.rect.LineEndOffset();
bfc_block_offset_ = opportunity.rect.BlockStartOffset();
line_.line_opportunity = line_opportunity;
}
bool NGLineBreaker::NextLine(const NGLayoutOpportunity& opportunity,
bool NGLineBreaker::NextLine(const NGLineLayoutOpportunity& line_opportunity,
NGLineInfo* line_info) {
bfc_block_offset_ = constraint_space_.BfcOffset().block_offset;
PrepareNextLine(opportunity, line_info);
PrepareNextLine(line_opportunity, line_info);
BreakLine(line_info);
if (line_info->Results().IsEmpty())
......@@ -294,14 +290,14 @@ void NGLineBreaker::UpdatePosition(const NGInlineItemResults& results) {
}
void NGLineBreaker::ComputeLineLocation(NGLineInfo* line_info) const {
LayoutUnit bfc_line_offset = line_.line_left_bfc_offset;
LayoutUnit bfc_line_offset = line_.line_opportunity.line_left_offset;
LayoutUnit available_width = line_.AvailableWidth();
// Negative margins can make the position negative, but the inline size is
// always positive or 0.
line_info->SetLineBfcOffset({bfc_line_offset, bfc_block_offset_},
available_width,
line_.position.ClampNegativeToZero());
line_info->SetLineBfcOffset(
{bfc_line_offset, line_.line_opportunity.bfc_block_offset},
available_width, line_.position.ClampNegativeToZero());
}
NGLineBreaker::LineBreakState NGLineBreaker::HandleText(
......@@ -397,7 +393,7 @@ void NGLineBreaker::BreakText(NGInlineItemResult* item_result,
// * If offset == item.EndOffset(): the break opportunity at the end fits,
// or the first break opportunity is beyond the end.
// There may be room for more characters.
// * If width > available_width: The first break opporunity does not fit.
// * If width > available_width: The first break opportunity does not fit.
// offset is the first break opportunity, either inside, at the end, or
// beyond the end.
if (item_result->end_offset < item.EndOffset()) {
......@@ -643,8 +639,6 @@ void NGLineBreaker::HandleAtomicInline(const NGInlineItem& item,
// We have this check if there are already UnpositionedFloats as we aren't
// allowed to position a float "above" another float which has come before us
// in the document.
//
// TODO(glebl): Add the support of clearance for inline floats.
void NGLineBreaker::HandleFloat(const NGInlineItem& item,
NGLineInfo* line_info,
NGInlineItemResult* item_result) {
......@@ -691,6 +685,8 @@ void NGLineBreaker::HandleFloat(const NGInlineItem& item,
margins.InlineSum())
.ClampNegativeToZero();
LayoutUnit bfc_block_offset = line_.line_opportunity.bfc_block_offset;
// The float should be positioned after the current line if:
// - It can't fit.
// - It will be moved down due to block-start edge alignment.
......@@ -700,9 +696,9 @@ void NGLineBreaker::HandleFloat(const NGInlineItem& item,
// the line breaker has run).
bool float_after_line =
!line_.CanFit(inline_margin_size) ||
exclusion_space_->LastFloatBlockStart() > bfc_block_offset_ ||
exclusion_space_->LastFloatBlockStart() > bfc_block_offset ||
exclusion_space_->ClearanceOffset(float_style.Clear()) >
bfc_block_offset_ ||
bfc_block_offset ||
mode_ != NGLineBreakerMode::kContent;
// Check if we already have a pending float. That's because a float cannot be
......@@ -711,30 +707,26 @@ void NGLineBreaker::HandleFloat(const NGInlineItem& item,
AddUnpositionedFloat(unpositioned_floats_, container_builder_,
std::move(unpositioned_float));
} else {
LayoutUnit origin_block_offset = bfc_block_offset_;
NGPositionedFloat positioned_float = PositionFloat(
origin_block_offset, constraint_space_.BfcOffset().block_offset,
bfc_block_offset, constraint_space_.BfcOffset().block_offset,
unpositioned_float.get(), constraint_space_, exclusion_space_);
positioned_floats_->push_back(positioned_float);
DCHECK_EQ(positioned_float.bfc_offset.block_offset,
bfc_block_offset_ + margins.block_start);
bfc_block_offset + margins.block_start);
if (float_style.Floating() == EFloat::kLeft) {
line_.line_left_bfc_offset = std::max(
line_.line_left_bfc_offset,
line_.line_opportunity.line_left_offset = std::max(
line_.line_opportunity.line_left_offset,
positioned_float.bfc_offset.line_offset + inline_margin_size -
margins.LineLeft(TextDirection::kLtr));
} else {
line_.line_right_bfc_offset =
std::min(line_.line_right_bfc_offset,
line_.line_opportunity.line_right_offset =
std::min(line_.line_opportunity.line_right_offset,
positioned_float.bfc_offset.line_offset -
margins.LineLeft(TextDirection::kLtr));
}
DCHECK_GE(line_.line_left_bfc_offset, LayoutUnit());
DCHECK_GE(line_.line_right_bfc_offset, LayoutUnit());
DCHECK_GE(line_.AvailableWidth(), LayoutUnit());
}
}
......@@ -930,7 +922,7 @@ NGLineBreaker::LineBreakState NGLineBreaker::HandleOverflow(
}
// Let this line overflow.
// If there was a break opporunity, the overflow should stop there.
// If there was a break opportunity, the overflow should stop there.
if (break_before) {
Rewind(line_info, break_before);
return LineBreakState::kTrailing;
......
......@@ -6,7 +6,7 @@
#define NGLineBreaker_h
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/ng/exclusions/ng_layout_opportunity.h"
#include "third_party/blink/renderer/core/layout/ng/exclusions/ng_line_layout_opportunity.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
#include "third_party/blink/renderer/platform/fonts/shaping/harf_buzz_shaper.h"
......@@ -47,7 +47,7 @@ class CORE_EXPORT NGLineBreaker {
// Compute the next line break point and produces NGInlineItemResults for
// the line.
bool NextLine(const NGLayoutOpportunity&, NGLineInfo*);
bool NextLine(const NGLineLayoutOpportunity& line_opportunity, NGLineInfo*);
// Create an NGInlineBreakToken for the last line returned by NextLine().
scoped_refptr<NGInlineBreakToken> CreateBreakToken(
......@@ -71,11 +71,7 @@ class CORE_EXPORT NGLineBreaker {
// that computes position in visual order, this position in logical order.
LayoutUnit position;
// The current opportunity.
NGLayoutOpportunity opportunity;
LayoutUnit line_left_bfc_offset;
LayoutUnit line_right_bfc_offset;
NGLineLayoutOpportunity line_opportunity;
// True if this line is the "first formatted line".
// https://www.w3.org/TR/CSS22/selector.html#first-formatted-line
......@@ -95,8 +91,7 @@ class CORE_EXPORT NGLineBreaker {
bool is_after_forced_break = false;
LayoutUnit AvailableWidth() const {
DCHECK_GE(line_right_bfc_offset, line_left_bfc_offset);
return line_right_bfc_offset - line_left_bfc_offset;
return line_opportunity.AvailableInlineSize();
}
bool CanFit() const { return position <= AvailableWidth(); }
bool CanFit(LayoutUnit extra) const {
......@@ -116,7 +111,7 @@ class CORE_EXPORT NGLineBreaker {
void BreakLine(NGLineInfo*);
void PrepareNextLine(const NGLayoutOpportunity&, NGLineInfo*);
void PrepareNextLine(const NGLineLayoutOpportunity&, NGLineInfo*);
void UpdatePosition(const NGInlineItemResults&);
void ComputeLineLocation(NGLineInfo*) const;
......@@ -187,8 +182,6 @@ class CORE_EXPORT NGLineBreaker {
HarfBuzzShaper shaper_;
ShapeResultSpacing<String> spacing_;
bool previous_line_had_forced_break_ = false;
LayoutUnit bfc_line_offset_;
LayoutUnit bfc_block_offset_;
const Hyphenation* hyphenation_ = nullptr;
// Keep track of handled float items. See HandleFloat().
......
......@@ -46,16 +46,14 @@ class NGLineBreakerTest : public NGBaseLayoutAlgorithmTest {
Vector<NGInlineItemResults> lines;
NGExclusionSpace exclusion_space;
NGLayoutOpportunity opportunity;
opportunity.rect =
NGBfcRect(NGBfcOffset(), {available_width, LayoutUnit::Max()});
NGLineLayoutOpportunity line_opportunity(available_width);
NGLineInfo line_info;
while (!break_token || !break_token->IsFinished()) {
NGLineBreaker line_breaker(node, NGLineBreakerMode::kContent, *space,
&positioned_floats, &unpositioned_floats,
/* container_builder */ nullptr,
&exclusion_space, 0u, break_token.get());
if (!line_breaker.NextLine(opportunity, &line_info))
if (!line_breaker.NextLine(line_opportunity, &line_info))
break;
break_token = line_breaker.CreateBreakToken(line_info, nullptr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment