[text-wrap-pretty] Add NGLineBreaker::OverrideAvailableWidth
When asking `NGLineBreaker` to layout within a specified available width, instead of passing a artificially modified `line_opportunity`, this patch adds `OverrideAvailableWidth`. The `line_opportunity` has effects other than available width, such as BFC offsets, floating objects, and when it's copied to `NGLineInfo`, the line width to apply `text-align`. The last one was fixed in crrev.com/c/4304620 by saving and restoring the `line_opportunity`. To make the intention clearer and allow `NGLineBreaker` to behave differently in that situation, `OverrideAvailableWidth` tells that callsites want to use different available width than the `line_opportunity`, only for computing line wrapping purposes. Bug: 1432798 Change-Id: I610afa1722de1bb60e49d86abc36b53c64eb3dca Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4533817 Auto-Submit: Koji Ishii <kojii@chromium.org> Reviewed-by: Kent Tamura <tkent@chromium.org> Commit-Queue: Kent Tamura <tkent@chromium.org> Cr-Commit-Position: refs/heads/main@{#1144578}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
a6dc0beca2
commit
fa2d839111
third_party/blink/renderer/core/layout/ng/inline
@ -1321,7 +1321,6 @@ const NGLayoutResult* NGInlineLayoutAlgorithm::Layout() {
|
||||
Node(), ConstraintSpace(), line_opportunity));
|
||||
}
|
||||
|
||||
absl::optional<NGLineLayoutOpportunity> saved_line_opportunity;
|
||||
bool is_line_info_cached = false;
|
||||
NGLineInfo& line_info =
|
||||
context_->GetLineInfo(break_token, is_line_info_cached);
|
||||
@ -1330,17 +1329,14 @@ const NGLayoutResult* NGInlineLayoutAlgorithm::Layout() {
|
||||
// `line_info` was cached.
|
||||
line_info.SetBfcBlockOffset(line_opportunity.bfc_block_offset);
|
||||
} else {
|
||||
if (const absl::optional<LayoutUnit>& balanced_available_width =
|
||||
context_->BalancedAvailableWidth()) {
|
||||
saved_line_opportunity = line_opportunity;
|
||||
NGParagraphLineBreaker::PrepareForNextLine(*balanced_available_width,
|
||||
&line_opportunity);
|
||||
}
|
||||
|
||||
NGLineBreaker line_breaker(
|
||||
Node(), NGLineBreakerMode::kContent, ConstraintSpace(),
|
||||
line_opportunity, leading_floats, handled_leading_floats_index,
|
||||
break_token, column_spanner_path_, &ExclusionSpace());
|
||||
if (const absl::optional<LayoutUnit>& balanced_available_width =
|
||||
context_->BalancedAvailableWidth()) {
|
||||
line_breaker.OverrideAvailableWidth(*balanced_available_width);
|
||||
}
|
||||
line_breaker.NextLine(&line_info);
|
||||
}
|
||||
|
||||
@ -1425,12 +1421,6 @@ const NGLayoutResult* NGInlineLayoutAlgorithm::Layout() {
|
||||
// to overflow in that case.
|
||||
}
|
||||
|
||||
if (saved_line_opportunity) {
|
||||
// Restore `line_opportunity` if `NGParagraphLineBreaker` updated it.
|
||||
line_opportunity = *saved_line_opportunity;
|
||||
line_info.SetAvailableWidth(line_opportunity.AvailableInlineSize());
|
||||
}
|
||||
|
||||
PrepareBoxStates(line_info, break_token);
|
||||
|
||||
CreateLine(line_opportunity, &line_info, line_box);
|
||||
|
@ -328,8 +328,13 @@ inline bool NGLineBreaker::ShouldAutoWrap(const ComputedStyle& style) const {
|
||||
return style.ShouldWrapLine();
|
||||
}
|
||||
|
||||
LayoutUnit NGLineBreaker::ComputeAvailableWidth() const {
|
||||
LayoutUnit available_width = line_opportunity_.AvailableInlineSize();
|
||||
void NGLineBreaker::UpdateAvailableWidth() {
|
||||
LayoutUnit available_width;
|
||||
if (UNLIKELY(override_available_width_)) {
|
||||
available_width = override_available_width_;
|
||||
} else {
|
||||
available_width = line_opportunity_.AvailableInlineSize();
|
||||
}
|
||||
// Make sure it's at least the initial size, which is usually 0 but not so
|
||||
// when `box-decoration-break: clone`.
|
||||
available_width =
|
||||
@ -337,7 +342,7 @@ LayoutUnit NGLineBreaker::ComputeAvailableWidth() const {
|
||||
// Available width must be smaller than |LayoutUnit::Max()| so that the
|
||||
// position can be larger.
|
||||
available_width = std::min(available_width, LayoutUnit::NearlyMax());
|
||||
return available_width;
|
||||
available_width_ = available_width;
|
||||
}
|
||||
|
||||
NGLineBreaker::NGLineBreaker(NGInlineNode node,
|
||||
@ -377,7 +382,7 @@ NGLineBreaker::NGLineBreaker(NGInlineNode node,
|
||||
leading_floats_(leading_floats),
|
||||
handled_leading_floats_index_(handled_leading_floats_index),
|
||||
base_direction_(node_.BaseDirection()) {
|
||||
available_width_ = ComputeAvailableWidth();
|
||||
UpdateAvailableWidth();
|
||||
break_iterator_.SetBreakSpace(BreakSpaceType::kAfterSpaceRun);
|
||||
if (is_svg_text_) {
|
||||
const auto& char_data_list = node_.SvgCharacterDataList();
|
||||
@ -421,6 +426,12 @@ NGLineBreaker::NGLineBreaker(NGInlineNode node,
|
||||
|
||||
NGLineBreaker::~NGLineBreaker() = default;
|
||||
|
||||
void NGLineBreaker::OverrideAvailableWidth(LayoutUnit available_width) {
|
||||
DCHECK(available_width);
|
||||
override_available_width_ = available_width;
|
||||
UpdateAvailableWidth();
|
||||
}
|
||||
|
||||
inline NGInlineItemResult* NGLineBreaker::AddItem(const NGInlineItem& item,
|
||||
unsigned end_offset,
|
||||
NGLineInfo* line_info) {
|
||||
@ -545,7 +556,7 @@ void NGLineBreaker::RecalcClonedBoxDecorations() {
|
||||
// accommodate cloned box decorations.
|
||||
position_ += cloned_box_decorations_initial_size_;
|
||||
// |cloned_box_decorations_initial_size_| may affect available width.
|
||||
available_width_ = ComputeAvailableWidth();
|
||||
UpdateAvailableWidth();
|
||||
DCHECK_GE(available_width_, cloned_box_decorations_initial_size_);
|
||||
}
|
||||
|
||||
@ -721,6 +732,12 @@ void NGLineBreaker::NextLine(NGLineInfo* line_info) {
|
||||
if (trailing_whitespace_ == WhitespaceState::kPreserved)
|
||||
line_info->SetHasTrailingSpaces();
|
||||
|
||||
if (UNLIKELY(override_available_width_)) {
|
||||
// Clear the overridden available width so that `line_info` has the original
|
||||
// available width for aligning.
|
||||
override_available_width_ = LayoutUnit();
|
||||
UpdateAvailableWidth();
|
||||
}
|
||||
ComputeLineLocation(line_info);
|
||||
if (mode_ == NGLineBreakerMode::kContent) {
|
||||
line_info->SetBreakToken(CreateBreakToken(*line_info));
|
||||
@ -2701,7 +2718,7 @@ void NGLineBreaker::HandleFloat(const NGInlineItem& item,
|
||||
|
||||
line_opportunity_ = opportunity.ComputeLineLayoutOpportunity(
|
||||
constraint_space_, line_opportunity_.line_block_size, LayoutUnit());
|
||||
available_width_ = ComputeAvailableWidth();
|
||||
UpdateAvailableWidth();
|
||||
|
||||
DCHECK_GE(AvailableWidth(), LayoutUnit());
|
||||
}
|
||||
|
@ -61,6 +61,10 @@ class CORE_EXPORT NGLineBreaker {
|
||||
|
||||
bool IsFinished() const { return current_.item_index >= Items().size(); }
|
||||
|
||||
// Override the available width to compute line breaks. This is reset after
|
||||
// each `NextLine`.
|
||||
void OverrideAvailableWidth(LayoutUnit available_width);
|
||||
|
||||
// Computing |NGLineBreakerMode::kMinContent| with |MaxSizeCache| caches
|
||||
// information that can help computing |kMaxContent|. It is recommended to set
|
||||
// this when computing both |kMinContent| and |kMaxContent|.
|
||||
@ -216,10 +220,7 @@ class CORE_EXPORT NGLineBreaker {
|
||||
void ComputeBaseDirection();
|
||||
void RecalcClonedBoxDecorations();
|
||||
|
||||
LayoutUnit AvailableWidth() const {
|
||||
DCHECK_EQ(available_width_, ComputeAvailableWidth());
|
||||
return available_width_;
|
||||
}
|
||||
LayoutUnit AvailableWidth() const { return available_width_; }
|
||||
LayoutUnit AvailableWidthToFit() const {
|
||||
return AvailableWidth().AddEpsilon();
|
||||
}
|
||||
@ -227,7 +228,7 @@ class CORE_EXPORT NGLineBreaker {
|
||||
return AvailableWidthToFit() - position_;
|
||||
}
|
||||
bool CanFitOnLine() const { return position_ <= AvailableWidthToFit(); }
|
||||
LayoutUnit ComputeAvailableWidth() const;
|
||||
void UpdateAvailableWidth();
|
||||
|
||||
// True if the current line is hyphenated.
|
||||
bool HasHyphen() const { return hyphen_index_.has_value(); }
|
||||
@ -349,6 +350,8 @@ class CORE_EXPORT NGLineBreaker {
|
||||
};
|
||||
absl::optional<TrailingCollapsibleSpace> trailing_collapsible_space_;
|
||||
|
||||
LayoutUnit override_available_width_;
|
||||
|
||||
// Keep track of handled float items. See HandleFloat().
|
||||
const NGPositionedFloatVector& leading_floats_;
|
||||
unsigned leading_floats_index_ = 0u;
|
||||
|
@ -150,9 +150,6 @@ class CORE_EXPORT NGLineInfo {
|
||||
void SetBfcBlockOffset(LayoutUnit block_offset) {
|
||||
bfc_offset_.block_offset = block_offset;
|
||||
}
|
||||
void SetAvailableWidth(LayoutUnit available_width) {
|
||||
available_width_ = available_width;
|
||||
}
|
||||
void SetWidth(LayoutUnit available_width, LayoutUnit width) {
|
||||
available_width_ = available_width;
|
||||
width_ = width;
|
||||
|
@ -227,18 +227,4 @@ NGParagraphLineBreaker::AttemptParagraphBalancingCore(
|
||||
normal_lines.BreakToken());
|
||||
}
|
||||
|
||||
// static
|
||||
void NGParagraphLineBreaker::PrepareForNextLine(
|
||||
LayoutUnit balanced_available_width,
|
||||
NGLineLayoutOpportunity* line_opportunity) {
|
||||
DCHECK_GE(line_opportunity->line_right_offset,
|
||||
line_opportunity->line_left_offset);
|
||||
DCHECK_EQ(line_opportunity->line_left_offset,
|
||||
line_opportunity->float_line_left_offset);
|
||||
DCHECK_EQ(line_opportunity->line_right_offset,
|
||||
line_opportunity->float_line_right_offset);
|
||||
line_opportunity->line_right_offset =
|
||||
line_opportunity->line_left_offset + balanced_available_width;
|
||||
}
|
||||
|
||||
} // namespace blink
|
||||
|
@ -23,9 +23,6 @@ class CORE_EXPORT NGParagraphLineBreaker {
|
||||
const NGConstraintSpace& space,
|
||||
const NGLineLayoutOpportunity& line_opportunity);
|
||||
|
||||
static void PrepareForNextLine(LayoutUnit balanced_available_width,
|
||||
NGLineLayoutOpportunity* line_opportunity);
|
||||
|
||||
private:
|
||||
static absl::optional<LayoutUnit> AttemptParagraphBalancingCore(
|
||||
const NGInlineNode& node,
|
||||
|
Reference in New Issue
Block a user