Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(113)

Side by Side Diff: third_party/WebKit/Source/core/layout/ng/ng_line_builder.cc

Issue 2772503004: [LayoutNG] Add NGInlineBreakToken and back of NGInlineLayoutAlgorithm (Closed)
Patch Set: Rename Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "core/layout/ng/ng_line_builder.h"
6
7 #include "core/layout/BidiRun.h"
8 #include "core/layout/LayoutBlockFlow.h"
9 #include "core/layout/line/LineInfo.h"
10 #include "core/layout/line/RootInlineBox.h"
11 #include "core/layout/ng/layout_ng_block_flow.h"
12 #include "core/layout/ng/ng_bidi_paragraph.h"
13 #include "core/layout/ng/ng_block_layout_algorithm.h"
14 #include "core/layout/ng/ng_box_fragment.h"
15 #include "core/layout/ng/ng_constraint_space.h"
16 #include "core/layout/ng/ng_constraint_space_builder.h"
17 #include "core/layout/ng/ng_floating_object.h"
18 #include "core/layout/ng/ng_floats_utils.h"
19 #include "core/layout/ng/ng_fragment_builder.h"
20 #include "core/layout/ng/ng_inline_node.h"
21 #include "core/layout/ng/ng_length_utils.h"
22 #include "core/layout/ng/ng_line_box_fragment.h"
23 #include "core/layout/ng/ng_line_box_fragment_builder.h"
24 #include "core/layout/ng/ng_space_utils.h"
25 #include "core/layout/ng/ng_text_fragment.h"
26 #include "core/layout/ng/ng_text_fragment_builder.h"
27 #include "core/style/ComputedStyle.h"
28 #include "platform/text/BidiRunList.h"
29
30 namespace blink {
31 namespace {
32
33 RefPtr<NGConstraintSpace> CreateConstraintSpaceForFloat(
34 const ComputedStyle& style,
35 const NGConstraintSpace& parent_space,
36 NGConstraintSpaceBuilder* space_builder) {
37 DCHECK(space_builder) << "space_builder cannot be null here";
38 bool is_new_bfc =
39 IsNewFormattingContextForInFlowBlockLevelChild(parent_space, style);
40 return space_builder->SetIsNewFormattingContext(is_new_bfc)
41 .SetTextDirection(style.direction())
42 .SetIsShrinkToFit(ShouldShrinkToFit(parent_space, style))
43 .ToConstraintSpace(FromPlatformWritingMode(style.getWritingMode()));
44 }
45
46 NGLogicalOffset GetOriginPointForFloats(const NGConstraintSpace& space,
47 LayoutUnit content_size) {
48 NGLogicalOffset origin_point = space.BfcOffset();
49 origin_point.block_offset += content_size;
50 return origin_point;
51 }
52
53 void PositionPendingFloats(const NGLogicalOffset& origin_point,
54 NGConstraintSpace* space,
55 NGFragmentBuilder* builder) {
56 DCHECK(builder) << "Builder cannot be null here";
57
58 for (auto& floating_object : builder->UnpositionedFloats()) {
59 NGLogicalOffset offset = PositionFloat(origin_point, space->BfcOffset(),
60 floating_object.get(), space);
61 builder->AddFloatingObject(floating_object, offset);
62 }
63 builder->MutableUnpositionedFloats().clear();
64 }
65
66 } // namespace
67
68 NGLineBuilder::NGLineBuilder(NGInlineNode* inline_box,
69 NGConstraintSpace* constraint_space)
70 : inline_box_(inline_box),
71 constraint_space_(constraint_space),
72 container_builder_(NGPhysicalFragment::kFragmentBox, inline_box_),
73 container_layout_result_(nullptr),
74 is_horizontal_writing_mode_(
75 blink::IsHorizontalWritingMode(constraint_space->WritingMode())),
76 space_builder_(constraint_space)
77 #if DCHECK_IS_ON()
78 ,
79 is_bidi_reordered_(false)
80 #endif
81 {
82 if (!is_horizontal_writing_mode_)
83 baseline_type_ = FontBaseline::IdeographicBaseline;
84 }
85
86 bool NGLineBuilder::CanFitOnLine() const {
87 LayoutUnit available_size = current_opportunity_.InlineSize();
88 if (available_size == NGSizeIndefinite)
89 return true;
90 return end_position_ <= available_size;
91 }
92
93 bool NGLineBuilder::HasItems() const {
94 return start_offset_ != end_offset_;
95 }
96
97 bool NGLineBuilder::HasBreakOpportunity() const {
98 return start_offset_ != last_break_opportunity_offset_;
99 }
100
101 bool NGLineBuilder::HasItemsAfterLastBreakOpportunity() const {
102 return last_break_opportunity_offset_ != end_offset_;
103 }
104
105 void NGLineBuilder::SetStart(unsigned index, unsigned offset) {
106 inline_box_->AssertOffset(index, offset);
107
108 start_index_ = last_index_ = last_break_opportunity_index_ = index;
109 start_offset_ = end_offset_ = last_break_opportunity_offset_ = offset;
110 end_position_ = last_break_opportunity_position_ = LayoutUnit();
111
112 FindNextLayoutOpportunity();
113 }
114
115 void NGLineBuilder::SetEnd(unsigned new_end_offset) {
116 DCHECK_GT(new_end_offset, end_offset_);
117 const Vector<NGLayoutInlineItem>& items = inline_box_->Items();
118 DCHECK_LE(new_end_offset, items.back().EndOffset());
119
120 // SetEnd() while |new_end_offset| is beyond the current last item.
121 unsigned index = last_index_;
122 const NGLayoutInlineItem* item = &items[index];
123 if (new_end_offset > item->EndOffset()) {
124 if (end_offset_ < item->EndOffset()) {
125 SetEnd(index, item->EndOffset(),
126 InlineSize(*item, end_offset_, item->EndOffset()));
127 }
128 item = &items[++index];
129
130 while (new_end_offset > item->EndOffset()) {
131 SetEnd(index, item->EndOffset(), InlineSize(*item));
132 item = &items[++index];
133 }
134 }
135
136 SetEnd(index, new_end_offset, InlineSize(*item, end_offset_, new_end_offset));
137
138 // Include closing elements.
139 while (new_end_offset == item->EndOffset() && index < items.size() - 1) {
140 item = &items[++index];
141 if (item->Type() != NGLayoutInlineItem::kCloseTag)
142 break;
143 SetEnd(index, new_end_offset, InlineSize(*item));
144 }
145 }
146
147 void NGLineBuilder::SetEnd(unsigned index,
148 unsigned new_end_offset,
149 LayoutUnit inline_size_since_current_end) {
150 const Vector<NGLayoutInlineItem>& items = inline_box_->Items();
151 DCHECK_LE(new_end_offset, items.back().EndOffset());
152
153 // |new_end_offset| should be in the current item or next.
154 // TODO(kojii): Reconsider this restriction if needed.
155 DCHECK((index == last_index_ && new_end_offset > end_offset_) ||
156 (index == last_index_ + 1 && new_end_offset >= end_offset_ &&
157 end_offset_ == items[last_index_].EndOffset()));
158 const NGLayoutInlineItem& item = items[index];
159 item.AssertEndOffset(new_end_offset);
160
161 if (item.Type() == NGLayoutInlineItem::kFloating) {
162 LayoutAndPositionFloat(
163 LayoutUnit(end_position_) + inline_size_since_current_end,
164 item.GetLayoutObject());
165 }
166
167 last_index_ = index;
168 end_offset_ = new_end_offset;
169 end_position_ += inline_size_since_current_end;
170 }
171
172 void NGLineBuilder::SetBreakOpportunity() {
173 last_break_opportunity_index_ = last_index_;
174 last_break_opportunity_offset_ = end_offset_;
175 last_break_opportunity_position_ = end_position_;
176 }
177
178 void NGLineBuilder::SetStartOfHangables(unsigned offset) {
179 // TODO(kojii): Implement.
180 }
181
182 LayoutUnit NGLineBuilder::InlineSize(const NGLayoutInlineItem& item) {
183 if (item.Type() == NGLayoutInlineItem::kAtomicInline)
184 return InlineSizeFromLayout(item);
185 return item.InlineSize();
186 }
187
188 LayoutUnit NGLineBuilder::InlineSize(const NGLayoutInlineItem& item,
189 unsigned start_offset,
190 unsigned end_offset) {
191 if (item.StartOffset() == start_offset && item.EndOffset() == end_offset)
192 return InlineSize(item);
193 return item.InlineSize(start_offset, end_offset);
194 }
195
196 LayoutUnit NGLineBuilder::InlineSizeFromLayout(const NGLayoutInlineItem& item) {
197 return NGBoxFragment(ConstraintSpace().WritingMode(),
198 toNGPhysicalBoxFragment(
199 LayoutItem(item)->PhysicalFragment().get()))
200 .InlineSize();
201 }
202
203 const NGLayoutResult* NGLineBuilder::LayoutItem(
204 const NGLayoutInlineItem& item) {
205 // Returns the cached NGLayoutResult if available.
206 const Vector<NGLayoutInlineItem>& items = inline_box_->Items();
207 if (layout_results_.isEmpty())
208 layout_results_.resize(items.size());
209 unsigned index = std::distance(items.begin(), &item);
210 RefPtr<NGLayoutResult>* layout_result = &layout_results_[index];
211 if (*layout_result)
212 return layout_result->get();
213
214 DCHECK(item.Type() == NGLayoutInlineItem::kAtomicInline);
215 NGBlockNode* node = new NGBlockNode(item.GetLayoutObject());
216 // TODO(kojii): Keep node in NGLayoutInlineItem.
217 const ComputedStyle& style = node->Style();
218 NGConstraintSpaceBuilder constraint_space_builder(&ConstraintSpace());
219 RefPtr<NGConstraintSpace> constraint_space =
220 constraint_space_builder.SetIsNewFormattingContext(true)
221 .SetIsShrinkToFit(true)
222 .SetTextDirection(style.direction())
223 .ToConstraintSpace(FromPlatformWritingMode(style.getWritingMode()));
224 *layout_result = node->Layout(constraint_space.get());
225 return layout_result->get();
226 }
227
228 void NGLineBuilder::CreateLine() {
229 if (HasItemsAfterLastBreakOpportunity())
230 SetBreakOpportunity();
231 CreateLineUpToLastBreakOpportunity();
232 }
233
234 void NGLineBuilder::CreateLineUpToLastBreakOpportunity() {
235 const Vector<NGLayoutInlineItem>& items = inline_box_->Items();
236
237 // Create a list of LineItemChunk from |start| and |last_break_opportunity|.
238 // TODO(kojii): Consider refactoring LineItemChunk once NGLineBuilder's public
239 // API is more finalized. It does not fit well with the current API.
240 Vector<LineItemChunk, 32> line_item_chunks;
241 unsigned start_offset = start_offset_;
242 for (unsigned i = start_index_; i <= last_break_opportunity_index_; i++) {
243 const NGLayoutInlineItem& item = items[i];
244 unsigned end_offset =
245 std::min(item.EndOffset(), last_break_opportunity_offset_);
246 line_item_chunks.push_back(
247 LineItemChunk{i, start_offset, end_offset,
248 InlineSize(item, start_offset, end_offset)});
249 start_offset = end_offset;
250 }
251
252 if (inline_box_->IsBidiEnabled())
253 BidiReorder(&line_item_chunks);
254
255 PlaceItems(line_item_chunks);
256
257 // Prepare for the next line.
258 // Move |start| to |last_break_opportunity|, keeping items after
259 // |last_break_opportunity|.
260 start_index_ = last_break_opportunity_index_;
261 start_offset_ = last_break_opportunity_offset_;
262 DCHECK_GE(end_position_, last_break_opportunity_position_);
263 end_position_ -= last_break_opportunity_position_;
264 last_break_opportunity_position_ = LayoutUnit();
265 #if DCHECK_IS_ON()
266 is_bidi_reordered_ = false;
267 #endif
268
269 NGLogicalOffset origin_point =
270 GetOriginPointForFloats(ConstraintSpace(), content_size_);
271 PositionPendingFloats(origin_point, constraint_space_, &container_builder_);
272 FindNextLayoutOpportunity();
273 }
274
275 void NGLineBuilder::BidiReorder(Vector<LineItemChunk, 32>* line_item_chunks) {
276 #if DCHECK_IS_ON()
277 DCHECK(!is_bidi_reordered_);
278 is_bidi_reordered_ = true;
279 #endif
280
281 // TODO(kojii): UAX#9 L1 is not supported yet. Supporting L1 may change
282 // embedding levels of parts of runs, which requires to split items.
283 // http://unicode.org/reports/tr9/#L1
284 // BidiResolver does not support L1 crbug.com/316409.
285
286 // Create a list of chunk indices in the visual order.
287 // ICU |ubidi_getVisualMap()| works for a run of characters. Since we can
288 // handle the direction of each run, we use |ubidi_reorderVisual()| to reorder
289 // runs instead of characters.
290 Vector<UBiDiLevel, 32> levels;
291 levels.reserveInitialCapacity(line_item_chunks->size());
292 for (const auto& chunk : *line_item_chunks)
293 levels.push_back(inline_box_->Items()[chunk.index].BidiLevel());
294 Vector<int32_t, 32> indices_in_visual_order(line_item_chunks->size());
295 NGBidiParagraph::IndicesInVisualOrder(levels, &indices_in_visual_order);
296
297 // Reorder |line_item_chunks| in visual order.
298 Vector<LineItemChunk, 32> line_item_chunks_in_visual_order(
299 line_item_chunks->size());
300 for (unsigned visual_index = 0; visual_index < indices_in_visual_order.size();
301 visual_index++) {
302 unsigned logical_index = indices_in_visual_order[visual_index];
303 line_item_chunks_in_visual_order[visual_index] =
304 (*line_item_chunks)[logical_index];
305 }
306 line_item_chunks->swap(line_item_chunks_in_visual_order);
307 }
308
309 // TODO(glebl): Add the support of clearance for inline floats.
310 void NGLineBuilder::LayoutAndPositionFloat(LayoutUnit end_position,
311 LayoutObject* layout_object) {
312 LayoutNGBlockFlow* block_flow = toLayoutNGBlockFlow(layout_object);
313 NGBlockNode* node = new NGBlockNode(block_flow);
314
315 RefPtr<NGConstraintSpace> float_space = CreateConstraintSpaceForFloat(
316 node->Style(), ConstraintSpace(), &space_builder_);
317 // TODO(glebl): add the fragmentation support:
318 // same writing mode - get the inline size ComputeInlineSizeForFragment to
319 // determine if it fits on this line, then perform layout with the correct
320 // fragmentation line.
321 // diff writing mode - get the inline size from performing layout.
322 RefPtr<NGLayoutResult> layout_result = node->Layout(float_space.get());
323
324 NGBoxFragment float_fragment(
325 float_space->WritingMode(),
326 toNGPhysicalBoxFragment(layout_result->PhysicalFragment().get()));
327
328 RefPtr<NGFloatingObject> floating_object = NGFloatingObject::Create(
329 float_space.get(), constraint_space_, node->Style(), NGBoxStrut(),
330 layout_result->PhysicalFragment().get());
331
332 bool float_does_not_fit = end_position + float_fragment.InlineSize() >
333 current_opportunity_.InlineSize();
334 // Check if we already have a pending float. That's because a float cannot be
335 // higher than any block or floated box generated before.
336 if (!container_builder_.UnpositionedFloats().isEmpty() ||
337 float_does_not_fit) {
338 container_builder_.AddUnpositionedFloat(floating_object);
339 } else {
340 NGLogicalOffset origin_point =
341 GetOriginPointForFloats(ConstraintSpace(), content_size_);
342 NGLogicalOffset offset =
343 PositionFloat(origin_point, constraint_space_->BfcOffset(),
344 floating_object.get(), constraint_space_);
345 container_builder_.AddFloatingObject(floating_object, offset);
346 FindNextLayoutOpportunity();
347 }
348 }
349
350 void NGLineBuilder::PlaceItems(
351 const Vector<LineItemChunk, 32>& line_item_chunks) {
352 const Vector<NGLayoutInlineItem>& items = inline_box_->Items();
353
354 NGLineBoxFragmentBuilder line_box(inline_box_);
355 NGTextFragmentBuilder text_builder(inline_box_);
356
357 // Accumulate a "strut"; a zero-width inline box with the element's font and
358 // line height properties. https://drafts.csswg.org/css2/visudet.html#strut
359 const ComputedStyle* block_style = inline_box_->BlockStyle();
360 NGLineHeightMetrics block_metrics(*block_style, baseline_type_);
361 line_box.UniteMetrics(block_metrics);
362
363 // Use the block style to compute the estimated baseline position because the
364 // baseline position is not known until we know the maximum ascent and leading
365 // of the line. Items are placed on this baseline, then adjusted later if the
366 // estimation turned out to be different.
367 LayoutUnit estimated_baseline =
368 content_size_ + LayoutUnit(block_metrics.ascent_and_leading);
369
370 LayoutUnit inline_size;
371 for (const auto& line_item_chunk : line_item_chunks) {
372 const NGLayoutInlineItem& item = items[line_item_chunk.index];
373 // Skip bidi controls.
374 if (!item.GetLayoutObject())
375 continue;
376
377 LayoutUnit block_start;
378 if (item.Type() == NGLayoutInlineItem::kText) {
379 DCHECK(item.GetLayoutObject()->isText());
380 const ComputedStyle* style = item.Style();
381 // The direction of a fragment is the CSS direction to resolve logical
382 // properties, not the resolved bidi direction.
383 text_builder.SetDirection(style->direction())
384 .SetInlineSize(line_item_chunk.inline_size);
385
386 // |InlineTextBoxPainter| sets the baseline at |top +
387 // ascent-of-primary-font|. Compute |top| to match.
388 NGLineHeightMetrics metrics(*style, baseline_type_);
389 block_start = estimated_baseline - LayoutUnit(metrics.ascent);
390 text_builder.SetBlockSize(metrics.LineHeight());
391 line_box.UniteMetrics(metrics);
392
393 // Take all used fonts into account if 'line-height: normal'.
394 if (style->lineHeight().isNegative())
395 AccumulateUsedFonts(item, line_item_chunk, &line_box);
396 } else if (item.Type() == NGLayoutInlineItem::kAtomicInline) {
397 block_start =
398 PlaceAtomicInline(item, estimated_baseline, &line_box, &text_builder);
399 } else if (item.Type() == NGLayoutInlineItem::kOutOfFlowPositioned) {
400 // TODO(layout-dev): Report the correct static position for the out of
401 // flow descendant. We can't do this here yet as it doesn't know the
402 // size of the line box.
403 container_builder_.AddOutOfFlowDescendant(
404 // Absolute positioning blockifies the box's display type.
405 // https://drafts.csswg.org/css-display/#transformations
406 new NGBlockNode(item.GetLayoutObject()),
407 NGStaticPosition::Create(ConstraintSpace().WritingMode(),
408 ConstraintSpace().Direction(),
409 NGPhysicalOffset()));
410 continue;
411 } else {
412 continue;
413 }
414
415 RefPtr<NGPhysicalTextFragment> text_fragment = text_builder.ToTextFragment(
416 line_item_chunk.index, line_item_chunk.start_offset,
417 line_item_chunk.end_offset);
418
419 NGLogicalOffset logical_offset(
420 inline_size + current_opportunity_.InlineStartOffset() -
421 ConstraintSpace().BfcOffset().inline_offset,
422 block_start);
423 line_box.AddChild(std::move(text_fragment), logical_offset);
424 inline_size += line_item_chunk.inline_size;
425 }
426
427 if (line_box.Children().isEmpty()) {
428 // The line was empty.
429 return;
430 }
431
432 // If the estimated baseline position was not the actual position, move all
433 // fragments in the block direction.
434 LayoutUnit adjust_baseline(line_box.Metrics().ascent_and_leading -
435 block_metrics.ascent_and_leading);
436 if (adjust_baseline)
437 line_box.MoveChildrenInBlockDirection(adjust_baseline);
438
439 line_box.SetInlineSize(inline_size);
440 NGLogicalOffset offset(LayoutUnit(), content_size_);
441 container_builder_.AddChild(line_box.ToLineBoxFragment(), offset);
442 max_inline_size_ = std::max(max_inline_size_, inline_size);
443 content_size_ += line_box.Metrics().LineHeight();
444 }
445
446 void NGLineBuilder::AccumulateUsedFonts(const NGLayoutInlineItem& item,
447 const LineItemChunk& line_item_chunk,
448 NGLineBoxFragmentBuilder* line_box) {
449 HashSet<const SimpleFontData*> fallback_fonts;
450 item.GetFallbackFonts(&fallback_fonts, line_item_chunk.start_offset,
451 line_item_chunk.end_offset);
452 for (const auto& fallback_font : fallback_fonts) {
453 NGLineHeightMetrics metrics(fallback_font->getFontMetrics(),
454 baseline_type_);
455 line_box->UniteMetrics(metrics);
456 }
457 }
458
459 LayoutUnit NGLineBuilder::PlaceAtomicInline(
460 const NGLayoutInlineItem& item,
461 LayoutUnit estimated_baseline,
462 NGLineBoxFragmentBuilder* line_box,
463 NGTextFragmentBuilder* text_builder) {
464 NGBoxFragment fragment(
465 ConstraintSpace().WritingMode(),
466 toNGPhysicalBoxFragment(LayoutItem(item)->PhysicalFragment().get()));
467 // TODO(kojii): Margin and border in block progression not implemented yet.
468 LayoutUnit block_size = fragment.BlockSize();
469
470 // TODO(kojii): Try to eliminate the wrapping text fragment and use the
471 // |fragment| directly. Currently |CopyFragmentDataToLayoutBlockFlow|
472 // requires a text fragment.
473 text_builder->SetInlineSize(fragment.InlineSize()).SetBlockSize(block_size);
474
475 // TODO(kojii): Add baseline position to NGPhysicalFragment.
476 LayoutBox* box = toLayoutBox(item.GetLayoutObject());
477 LineDirectionMode line_direction_mode =
478 IsHorizontalWritingMode() ? LineDirectionMode::HorizontalLine
479 : LineDirectionMode::VerticalLine;
480 bool is_first_line = container_builder_.Children().isEmpty();
481 int baseline_offset =
482 box->baselinePosition(baseline_type_, is_first_line, line_direction_mode);
483 LayoutUnit block_start = estimated_baseline - baseline_offset;
484
485 NGLineHeightMetrics metrics;
486 metrics.ascent_and_leading = baseline_offset;
487 metrics.descent_and_leading = block_size - baseline_offset;
488 line_box->UniteMetrics(metrics);
489
490 // TODO(kojii): Figure out what to do with OOF in NGLayoutResult.
491 // Floats are ok because atomic inlines are BFC?
492
493 return block_start;
494 }
495
496 void NGLineBuilder::FindNextLayoutOpportunity() {
497 NGLogicalOffset iter_offset = constraint_space_->BfcOffset();
498 iter_offset.block_offset += content_size_;
499 auto* iter = constraint_space_->LayoutOpportunityIterator(iter_offset);
500 NGLayoutOpportunity opportunity = iter->Next();
501 if (!opportunity.IsEmpty())
502 current_opportunity_ = opportunity;
503 }
504
505 RefPtr<NGLayoutResult> NGLineBuilder::CreateFragments() {
506 DCHECK(!HasItems()) << "Must call CreateLine()";
507
508 // TODO(kojii): Check if the line box width should be content or available.
509 // TODO(kojii): Need to take constraint_space into account.
510 container_builder_.SetInlineSize(max_inline_size_)
511 .SetInlineOverflow(max_inline_size_)
512 .SetBlockSize(content_size_)
513 .SetBlockOverflow(content_size_);
514
515 container_layout_result_ = container_builder_.ToBoxFragment();
516 return container_layout_result_;
517 }
518
519 void NGLineBuilder::CopyFragmentDataToLayoutBlockFlow() {
520 LayoutBlockFlow* block = inline_box_->GetLayoutBlockFlow();
521 block->deleteLineBoxTree();
522
523 Vector<NGLayoutInlineItem>& items = inline_box_->Items();
524 Vector<unsigned, 32> text_offsets(items.size());
525 inline_box_->GetLayoutTextOffsets(&text_offsets);
526
527 Vector<const NGPhysicalFragment*, 32> fragments_for_bidi_runs;
528 fragments_for_bidi_runs.reserveInitialCapacity(items.size());
529 BidiRunList<BidiRun> bidi_runs;
530 LineInfo line_info;
531 NGPhysicalBoxFragment* box_fragment = toNGPhysicalBoxFragment(
532 container_layout_result_->PhysicalFragment().get());
533 for (const auto& container_child : box_fragment->Children()) {
534 NGPhysicalLineBoxFragment* physical_line_box =
535 toNGPhysicalLineBoxFragment(container_child.get());
536 // Create a BidiRunList for this line.
537 for (const auto& line_child : physical_line_box->Children()) {
538 const auto* text_fragment = toNGPhysicalTextFragment(line_child.get());
539 const NGLayoutInlineItem& item = items[text_fragment->ItemIndex()];
540 BidiRun* run;
541 if (item.Type() == NGLayoutInlineItem::kText) {
542 LayoutObject* layout_object = item.GetLayoutObject();
543 DCHECK(layout_object->isText());
544 unsigned text_offset = text_offsets[text_fragment->ItemIndex()];
545 run = new BidiRun(text_fragment->StartOffset() - text_offset,
546 text_fragment->EndOffset() - text_offset,
547 item.BidiLevel(), LineLayoutItem(layout_object));
548 layout_object->clearNeedsLayout();
549 } else if (item.Type() == NGLayoutInlineItem::kAtomicInline) {
550 LayoutObject* layout_object = item.GetLayoutObject();
551 DCHECK(layout_object->isAtomicInlineLevel());
552 run =
553 new BidiRun(0, 1, item.BidiLevel(), LineLayoutItem(layout_object));
554 } else {
555 continue;
556 }
557 bidi_runs.addRun(run);
558 fragments_for_bidi_runs.push_back(text_fragment);
559 }
560 // TODO(kojii): bidi needs to find the logical last run.
561 bidi_runs.setLogicallyLastRun(bidi_runs.lastRun());
562
563 // Create a RootInlineBox from BidiRunList. InlineBoxes created for the
564 // RootInlineBox are set to Bidirun::m_box.
565 line_info.setEmpty(false);
566 // TODO(kojii): Implement setFirstLine, LastLine, etc.
567 RootInlineBox* root_line_box = block->constructLine(bidi_runs, line_info);
568
569 // Copy fragments data to InlineBoxes.
570 DCHECK_EQ(fragments_for_bidi_runs.size(), bidi_runs.runCount());
571 BidiRun* run = bidi_runs.firstRun();
572 for (auto* physical_fragment : fragments_for_bidi_runs) {
573 DCHECK(run);
574 NGTextFragment fragment(ConstraintSpace().WritingMode(),
575 toNGPhysicalTextFragment(physical_fragment));
576 InlineBox* inline_box = run->m_box;
577 inline_box->setLogicalWidth(fragment.InlineSize());
578 inline_box->setLogicalLeft(fragment.InlineOffset());
579 inline_box->setLogicalTop(fragment.BlockOffset());
580 if (inline_box->getLineLayoutItem().isBox()) {
581 LineLayoutBox box(inline_box->getLineLayoutItem());
582 box.setLocation(inline_box->location());
583 }
584 run = run->next();
585 }
586 DCHECK(!run);
587
588 // Copy to RootInlineBox.
589 NGLineBoxFragment line_box(ConstraintSpace().WritingMode(),
590 physical_line_box);
591 root_line_box->setLogicalWidth(line_box.InlineSize());
592 LayoutUnit line_top_with_leading = line_box.BlockOffset();
593 root_line_box->setLogicalTop(line_top_with_leading);
594 const NGLineHeightMetrics& metrics = physical_line_box->Metrics();
595 LayoutUnit baseline =
596 line_top_with_leading + LayoutUnit(metrics.ascent_and_leading);
597 root_line_box->setLineTopBottomPositions(
598 baseline - LayoutUnit(metrics.ascent),
599 baseline + LayoutUnit(metrics.descent), line_top_with_leading,
600 baseline + LayoutUnit(metrics.descent_and_leading));
601
602 bidi_runs.deleteRuns();
603 fragments_for_bidi_runs.clear();
604 }
605 }
606 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698