Skip to content

Commit f982e88

Browse files
zakharvoitmibrunin
authored andcommitted
[Backport] Security bug 1227933
Cherry-pick of patch originally reviewed on https://chromium-review.googlesource.com/c/chromium/src/+/3068926: [M90-LTS] Fix nested inline box fragmentation Added base/containers/adapters.h dependency when cherry-picking to M90, otherwise |base::Reversed| couldn't be found. (It probably was included transitively in newer versions) 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 Change-Id: I7edcd209e1fdac06bab01b16d660383e7e9c37bd Commit-Queue: Koji Ishii <kojii@chromium.org> Cr-Original-Commit-Position: refs/heads/master@{#903356} Reviewed-by: Jana Grill <janagrill@google.com> Reviewed-by: Koji Ishii <kojii@chromium.org> Owners-Override: Jana Grill <janagrill@google.com> Commit-Queue: Zakhar Voit <voit@google.com> Cr-Commit-Position: refs/branch-heads/4430@{#1556} Cr-Branched-From: e5ce7dc4f7518237b3d9bb93cccca35d25216cbe-refs/heads/master@{#857950} Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
1 parent e67f957 commit f982e88

File tree

2 files changed

+63
-27
lines changed

2 files changed

+63
-27
lines changed

chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

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

7+
#include "base/containers/adapters.h"
78
#include "third_party/blink/renderer/core/layout/geometry/logical_offset.h"
89
#include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
910
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h"
@@ -387,13 +388,14 @@ void NGInlineLayoutStateStack::UpdateAfterReorder(
387388
box_data.fragment_start = box_data.fragment_end = 0;
388389

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

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

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

411413
unsigned NGInlineLayoutStateStack::UpdateBoxDataFragmentRange(
412414
NGLogicalLineItems* line_box,
413-
unsigned index) {
415+
unsigned index,
416+
Vector<BoxData>* fragmented_boxes) {
414417
// Find the first line box item that should create a box fragment.
415418
for (; index < line_box->size(); index++) {
416419
NGLogicalLineItem* start = &(*line_box)[index];
@@ -438,7 +441,7 @@ unsigned NGInlineLayoutStateStack::UpdateBoxDataFragmentRange(
438441
// It also changes other BoxData, but not the one we're dealing with here
439442
// because the update is limited only when its |box_data_index| is lower.
440443
while (end->box_data_index && end->box_data_index < box_data_index) {
441-
UpdateBoxDataFragmentRange(line_box, index);
444+
UpdateBoxDataFragmentRange(line_box, index, fragmented_boxes);
442445
}
443446

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

473-
void NGInlineLayoutStateStack::UpdateFragmentedBoxDataEdges() {
471+
void NGInlineLayoutStateStack::UpdateFragmentedBoxDataEdges(
472+
Vector<BoxData>* fragmented_boxes) {
473+
DCHECK(!fragmented_boxes->IsEmpty());
474+
// Append in the descending order of |fragmented_box_data_index| because the
475+
// indices will change as boxes are inserted into |box_data_list_|.
476+
std::sort(fragmented_boxes->begin(), fragmented_boxes->end(),
477+
[](const BoxData& a, const BoxData& b) {
478+
if (a.fragmented_box_data_index != b.fragmented_box_data_index) {
479+
return a.fragmented_box_data_index <
480+
b.fragmented_box_data_index;
481+
}
482+
DCHECK_NE(a.fragment_start, b.fragment_start);
483+
return a.fragment_start < b.fragment_start;
484+
});
485+
for (BoxData& fragmented_box : base::Reversed(*fragmented_boxes)) {
486+
// Insert the fragmented box to right after the box it was fragmented from.
487+
// The order in the |box_data_list_| is critical when propagating child
488+
// fragment data such as OOF to ancestors.
489+
const unsigned insert_at = fragmented_box.fragmented_box_data_index;
490+
DCHECK_GT(insert_at, 0u);
491+
fragmented_box.fragmented_box_data_index = 0;
492+
box_data_list_.insert(insert_at, fragmented_box);
493+
494+
// Adjust box data indices by the insertion.
495+
for (BoxData& box_data : box_data_list_) {
496+
if (box_data.fragmented_box_data_index >= insert_at)
497+
++box_data.fragmented_box_data_index;
498+
}
499+
500+
// Set the index of the last fragment to the original box. This is needed to
501+
// update fragment edges.
502+
const unsigned fragmented_from = insert_at - 1;
503+
if (!box_data_list_[fragmented_from].fragmented_box_data_index)
504+
box_data_list_[fragmented_from].fragmented_box_data_index = insert_at;
505+
}
506+
507+
// Move the line-right edge to the last fragment.
474508
for (BoxData& box_data : box_data_list_) {
475509
if (box_data.fragmented_box_data_index)
476510
box_data.UpdateFragmentEdges(box_data_list_);

chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -156,17 +156,6 @@ class CORE_EXPORT NGInlineLayoutStateStack {
156156
// reordering.
157157
void UpdateAfterReorder(NGLogicalLineItems*);
158158

159-
// Update start/end of the first BoxData found at |index|.
160-
//
161-
// If inline fragmentation is found, a new BoxData is added.
162-
//
163-
// Returns the index to process next. It should be given to the next call to
164-
// this function.
165-
unsigned UpdateBoxDataFragmentRange(NGLogicalLineItems*, unsigned index);
166-
167-
// Update edges of inline fragmented boxes.
168-
void UpdateFragmentedBoxDataEdges();
169-
170159
// Compute inline positions of fragments and boxes.
171160
LayoutUnit ComputeInlinePositions(NGLogicalLineItems*, LayoutUnit position);
172161

@@ -259,6 +248,19 @@ class CORE_EXPORT NGInlineLayoutStateStack {
259248
scoped_refptr<const NGLayoutResult> CreateBoxFragment(NGLogicalLineItems*);
260249
};
261250

251+
// Update start/end of the first BoxData found at |index|.
252+
//
253+
// If inline fragmentation is found, a new BoxData is added.
254+
//
255+
// Returns the index to process next. It should be given to the next call to
256+
// this function.
257+
unsigned UpdateBoxDataFragmentRange(NGLogicalLineItems*,
258+
unsigned index,
259+
Vector<BoxData>* fragmented_boxes);
260+
261+
// Update edges of inline fragmented boxes.
262+
void UpdateFragmentedBoxDataEdges(Vector<BoxData>* fragmented_boxes);
263+
262264
Vector<NGInlineBoxState, 4> stack_;
263265
Vector<BoxData, 4> box_data_list_;
264266

0 commit comments

Comments
 (0)