Browse Source

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

* chore: cherry-pick 1227933 from chromium

* chore: update patches

* Update .patches

* chore: update patches

Co-authored-by: Cheng Zhao <[email protected]>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
trop[bot] 3 years ago
parent
commit
5dbcb9fe10
2 changed files with 216 additions and 0 deletions
  1. 1 0
      patches/chromium/.patches
  2. 215 0
      patches/chromium/cherry-pick-1227933.patch

+ 1 - 0
patches/chromium/.patches

@@ -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 - 0
patches/chromium/cherry-pick-1227933.patch

@@ -0,0 +1,215 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Koji Ishii <[email protected]>
+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 <[email protected]>
+Reviewed-by: Yoshifumi Inoue <[email protected]>
+Cr-Original-Commit-Position: refs/heads/master@{#903356}
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3053212
+Commit-Queue: Rubber Stamper <[email protected]>
+Bot-Commit: Rubber Stamper <[email protected]>
+Auto-Submit: Koji Ishii <[email protected]>
+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:[email protected]">
++<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>