Skip to content

Commit d07208f

Browse files
zakharvoitmibrunin
authored andcommitted
[Backport] Security bug 1227933
Manual 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 6ed7e70 commit d07208f

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"
@@ -389,13 +390,14 @@ void NGInlineLayoutStateStack::UpdateAfterReorder(
389390
box_data.fragment_start = box_data.fragment_end = 0;
390391

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

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

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

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

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

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

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

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

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

0 commit comments

Comments
 (0)