Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: cherry-pick fix for 1227933 from chromium #30614

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions patches/chromium/.patches
Expand Up @@ -181,3 +181,4 @@ cherry-pick-3feda0244490.patch
cherry-pick-cd98d7c0dae9.patch
replace_first_of_two_waitableevents_in_creditcardaccessmanager.patch
cherry-pick-ac9dc1235e28.patch
cherry-pick-1227933.patch
215 changes: 215 additions & 0 deletions patches/chromium/cherry-pick-1227933.patch
@@ -0,0 +1,215 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Koji Ishii <kojii@chromium.org>
Date: Mon, 26 Jul 2021 07:09:18 +0000
Subject: Fix nested inline box fragmentation

This patch fixes when nested inline boxes are fragmented in a
line due to bidi reordering.

Before this change, the fragmented boxes are appended to the
end of |box_data_list_|. Then when |NGInlineLayoutStateStack::
CreateBoxFragments| creates inline boxes in the ascending
order of |box_data_list_|, it failed to add the fragmented
boxes into their parent inline boxes.

This is critical for out-of-flow positioned objects whose
containing block is an inline box, because they expect to be
propagated through all ancestor inline boxes.

|UpdateBoxDataFragmentRange| is a little tricky by appending
to a vector it is iterating. Changing it to insert to the
correct position makes the function even trickier. This patch
changes it to add fragmented boxes to a separate vector, and
let later process |UpdateFragmentedBoxDataEdges| to merge the
vector to |box_data_list_|.

(cherry picked from commit 9c8a39c14a9c80556468593cddf436f5047a16ce)

Bug: 1227933, 1229999
Change-Id: I7edcd209e1fdac06bab01b16d660383e7e9c37bd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3038308
Commit-Queue: Koji Ishii <kojii@chromium.org>
Reviewed-by: Yoshifumi Inoue <yosin@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#903356}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3053212
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Auto-Submit: Koji Ishii <kojii@chromium.org>
Cr-Commit-Position: refs/branch-heads/4577@{#145}
Cr-Branched-From: 761ddde228655e313424edec06497d0c56b0f3c4-refs/heads/master@{#902210}

diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
index c61298842eaa308b7ae863d6e1cf5457a8091dd2..f6fb0f03c3ec63c0c2de2b9501534108dea85422 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
@@ -4,6 +4,7 @@

#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h"

+#include "base/containers/adapters.h"
#include "third_party/blink/renderer/core/layout/geometry/logical_offset.h"
#include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h"
@@ -389,13 +390,14 @@ void NGInlineLayoutStateStack::UpdateAfterReorder(
box_data.fragment_start = box_data.fragment_end = 0;

// Scan children and update start/end from their box_data_index.
- unsigned box_count = box_data_list_.size();
+ Vector<BoxData> fragmented_boxes;
for (unsigned index = 0; index < line_box->size();)
- index = UpdateBoxDataFragmentRange(line_box, index);
+ index = UpdateBoxDataFragmentRange(line_box, index, &fragmented_boxes);

- // If any inline fragmentation due to BiDi reorder, adjust box edges.
- if (box_count != box_data_list_.size())
- UpdateFragmentedBoxDataEdges();
+ // If any inline fragmentation occurred due to BiDi reorder, append them and
+ // adjust box edges.
+ if (UNLIKELY(!fragmented_boxes.IsEmpty()))
+ UpdateFragmentedBoxDataEdges(&fragmented_boxes);

#if DCHECK_IS_ON()
// Check all BoxData have ranges.
@@ -412,7 +414,8 @@ void NGInlineLayoutStateStack::UpdateAfterReorder(

unsigned NGInlineLayoutStateStack::UpdateBoxDataFragmentRange(
NGLogicalLineItems* line_box,
- unsigned index) {
+ unsigned index,
+ Vector<BoxData>* fragmented_boxes) {
// Find the first line box item that should create a box fragment.
for (; index < line_box->size(); index++) {
NGLogicalLineItem* start = &(*line_box)[index];
@@ -440,7 +443,7 @@ unsigned NGInlineLayoutStateStack::UpdateBoxDataFragmentRange(
// It also changes other BoxData, but not the one we're dealing with here
// because the update is limited only when its |box_data_index| is lower.
while (end->box_data_index && end->box_data_index < box_data_index) {
- UpdateBoxDataFragmentRange(line_box, index);
+ UpdateBoxDataFragmentRange(line_box, index, fragmented_boxes);
}

if (box_data_index != end->box_data_index)
@@ -455,14 +458,9 @@ unsigned NGInlineLayoutStateStack::UpdateBoxDataFragmentRange(
} else {
// This box is fragmented by BiDi reordering. Add a new BoxData for the
// fragmented range.
- box_data_list_[box_data_index - 1].fragmented_box_data_index =
- box_data_list_.size();
- // Do not use `emplace_back()` here because adding to |box_data_list_| may
- // reallocate the buffer, but the `BoxData` ctor must run before the
- // reallocation. Create a new instance and |push_back()| instead.
- BoxData fragmented_box_data(box_data_list_[box_data_index - 1],
- start_index, index);
- box_data_list_.push_back(fragmented_box_data);
+ BoxData& fragmented_box = fragmented_boxes->emplace_back(
+ box_data_list_[box_data_index - 1], start_index, index);
+ fragmented_box.fragmented_box_data_index = box_data_index;
}
// If this box has parent boxes, we need to process it again.
if (box_data_list_[box_data_index - 1].parent_box_data_index)
@@ -472,7 +470,43 @@ unsigned NGInlineLayoutStateStack::UpdateBoxDataFragmentRange(
return index;
}

-void NGInlineLayoutStateStack::UpdateFragmentedBoxDataEdges() {
+void NGInlineLayoutStateStack::UpdateFragmentedBoxDataEdges(
+ Vector<BoxData>* fragmented_boxes) {
+ DCHECK(!fragmented_boxes->IsEmpty());
+ // Append in the descending order of |fragmented_box_data_index| because the
+ // indices will change as boxes are inserted into |box_data_list_|.
+ std::sort(fragmented_boxes->begin(), fragmented_boxes->end(),
+ [](const BoxData& a, const BoxData& b) {
+ if (a.fragmented_box_data_index != b.fragmented_box_data_index) {
+ return a.fragmented_box_data_index <
+ b.fragmented_box_data_index;
+ }
+ DCHECK_NE(a.fragment_start, b.fragment_start);
+ return a.fragment_start < b.fragment_start;
+ });
+ for (BoxData& fragmented_box : base::Reversed(*fragmented_boxes)) {
+ // Insert the fragmented box to right after the box it was fragmented from.
+ // The order in the |box_data_list_| is critical when propagating child
+ // fragment data such as OOF to ancestors.
+ const unsigned insert_at = fragmented_box.fragmented_box_data_index;
+ DCHECK_GT(insert_at, 0u);
+ fragmented_box.fragmented_box_data_index = 0;
+ box_data_list_.insert(insert_at, fragmented_box);
+
+ // Adjust box data indices by the insertion.
+ for (BoxData& box_data : box_data_list_) {
+ if (box_data.fragmented_box_data_index >= insert_at)
+ ++box_data.fragmented_box_data_index;
+ }
+
+ // Set the index of the last fragment to the original box. This is needed to
+ // update fragment edges.
+ const unsigned fragmented_from = insert_at - 1;
+ if (!box_data_list_[fragmented_from].fragmented_box_data_index)
+ box_data_list_[fragmented_from].fragmented_box_data_index = insert_at;
+ }
+
+ // Move the line-right edge to the last fragment.
for (BoxData& box_data : box_data_list_) {
if (box_data.fragmented_box_data_index)
box_data.UpdateFragmentEdges(box_data_list_);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
index 36aa27914a6598671c3f9266f323ab03847db5a6..7fb13383a21116ce1dd17a327ad2cc911c3f7c01 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
@@ -157,17 +157,6 @@ class CORE_EXPORT NGInlineLayoutStateStack {
// reordering.
void UpdateAfterReorder(NGLogicalLineItems*);

- // Update start/end of the first BoxData found at |index|.
- //
- // If inline fragmentation is found, a new BoxData is added.
- //
- // Returns the index to process next. It should be given to the next call to
- // this function.
- unsigned UpdateBoxDataFragmentRange(NGLogicalLineItems*, unsigned index);
-
- // Update edges of inline fragmented boxes.
- void UpdateFragmentedBoxDataEdges();
-
// Compute inline positions of fragments and boxes.
LayoutUnit ComputeInlinePositions(NGLogicalLineItems*, LayoutUnit position);

@@ -260,6 +249,19 @@ class CORE_EXPORT NGInlineLayoutStateStack {
scoped_refptr<const NGLayoutResult> CreateBoxFragment(NGLogicalLineItems*);
};

+ // Update start/end of the first BoxData found at |index|.
+ //
+ // If inline fragmentation is found, a new BoxData is added.
+ //
+ // Returns the index to process next. It should be given to the next call to
+ // this function.
+ unsigned UpdateBoxDataFragmentRange(NGLogicalLineItems*,
+ unsigned index,
+ Vector<BoxData>* fragmented_boxes);
+
+ // Update edges of inline fragmented boxes.
+ void UpdateFragmentedBoxDataEdges(Vector<BoxData>* fragmented_boxes);
+
Vector<NGInlineBoxState, 4> stack_;
Vector<BoxData, 4> box_data_list_;

diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/text/crashtests/bidi-inline-fragment-oof-crash.html b/third_party/blink/web_tests/external/wpt/css/CSS2/text/crashtests/bidi-inline-fragment-oof-crash.html
new file mode 100644
index 0000000000000000000000000000000000000000..b701d2b5688ace54aa99530c12fa8143f1e6a508
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/text/crashtests/bidi-inline-fragment-oof-crash.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<link rel="author" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://crbug.com/1229999">
+<div style="direction:rtl; width:500px">
+ <span style="border:solid">
+ <span style="position:relative">
+ <div style="display:inline-block; width:1000%; height:10px"></div>
+ <span dir="ltr">
+ <div style="position:absolute"></div>
+ </span>
+ </span>
+ </span>
+</div>