| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "core/layout/ng/inline/ng_inline_layout_algorithm.h" | 5 #include "core/layout/ng/inline/ng_inline_layout_algorithm.h" |
| 6 | 6 |
| 7 #include "core/layout/ng/inline/ng_bidi_paragraph.h" | 7 #include "core/layout/ng/inline/ng_bidi_paragraph.h" |
| 8 #include "core/layout/ng/inline/ng_inline_break_token.h" | 8 #include "core/layout/ng/inline/ng_inline_break_token.h" |
| 9 #include "core/layout/ng/inline/ng_inline_node.h" | 9 #include "core/layout/ng/inline/ng_inline_node.h" |
| 10 #include "core/layout/ng/inline/ng_line_box_fragment.h" | 10 #include "core/layout/ng/inline/ng_line_box_fragment.h" |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 264 BidiReorder(&line_item_chunks); | 264 BidiReorder(&line_item_chunks); |
| 265 | 265 |
| 266 if (!PlaceItems(line_item_chunks)) | 266 if (!PlaceItems(line_item_chunks)) |
| 267 return false; | 267 return false; |
| 268 | 268 |
| 269 // Prepare for the next line. | 269 // Prepare for the next line. |
| 270 // Move |start| to |last_break_opportunity|, keeping items after | 270 // Move |start| to |last_break_opportunity|, keeping items after |
| 271 // |last_break_opportunity|. | 271 // |last_break_opportunity|. |
| 272 start_index_ = last_break_opportunity_index_; | 272 start_index_ = last_break_opportunity_index_; |
| 273 start_offset_ = last_break_opportunity_offset_; | 273 start_offset_ = last_break_opportunity_offset_; |
| 274 // If the offset is at the end of the item, move to the next item. |
| 275 if (start_offset_ == items[start_index_].EndOffset() && |
| 276 start_index_ < items.size() - 1) { |
| 277 start_index_++; |
| 278 } |
| 274 DCHECK_GE(end_position_, last_break_opportunity_position_); | 279 DCHECK_GE(end_position_, last_break_opportunity_position_); |
| 275 end_position_ -= last_break_opportunity_position_; | 280 end_position_ -= last_break_opportunity_position_; |
| 276 last_break_opportunity_position_ = LayoutUnit(); | 281 last_break_opportunity_position_ = LayoutUnit(); |
| 277 #if DCHECK_IS_ON() | 282 #if DCHECK_IS_ON() |
| 278 is_bidi_reordered_ = false; | 283 is_bidi_reordered_ = false; |
| 279 #endif | 284 #endif |
| 280 | 285 |
| 281 NGLogicalOffset origin_point = | 286 NGLogicalOffset origin_point = |
| 282 GetOriginPointForFloats(ConstraintSpace(), content_size_); | 287 GetOriginPointForFloats(ConstraintSpace(), content_size_); |
| 283 PositionPendingFloats(origin_point.block_offset, MutableConstraintSpace(), | 288 PositionPendingFloats(origin_point.block_offset, MutableConstraintSpace(), |
| (...skipping 13 matching lines...) Expand all Loading... |
| 297 // embedding levels of parts of runs, which requires to split items. | 302 // embedding levels of parts of runs, which requires to split items. |
| 298 // http://unicode.org/reports/tr9/#L1 | 303 // http://unicode.org/reports/tr9/#L1 |
| 299 // BidiResolver does not support L1 crbug.com/316409. | 304 // BidiResolver does not support L1 crbug.com/316409. |
| 300 | 305 |
| 301 // Create a list of chunk indices in the visual order. | 306 // Create a list of chunk indices in the visual order. |
| 302 // ICU |ubidi_getVisualMap()| works for a run of characters. Since we can | 307 // ICU |ubidi_getVisualMap()| works for a run of characters. Since we can |
| 303 // handle the direction of each run, we use |ubidi_reorderVisual()| to reorder | 308 // handle the direction of each run, we use |ubidi_reorderVisual()| to reorder |
| 304 // runs instead of characters. | 309 // runs instead of characters. |
| 305 Vector<UBiDiLevel, 32> levels; | 310 Vector<UBiDiLevel, 32> levels; |
| 306 levels.ReserveInitialCapacity(line_item_chunks->size()); | 311 levels.ReserveInitialCapacity(line_item_chunks->size()); |
| 312 const Vector<NGLayoutInlineItem>& items = Node()->Items(); |
| 307 for (const auto& chunk : *line_item_chunks) | 313 for (const auto& chunk : *line_item_chunks) |
| 308 levels.push_back(Node()->Items()[chunk.index].BidiLevel()); | 314 levels.push_back(items[chunk.index].BidiLevel()); |
| 309 Vector<int32_t, 32> indices_in_visual_order(line_item_chunks->size()); | 315 Vector<int32_t, 32> indices_in_visual_order(line_item_chunks->size()); |
| 310 NGBidiParagraph::IndicesInVisualOrder(levels, &indices_in_visual_order); | 316 NGBidiParagraph::IndicesInVisualOrder(levels, &indices_in_visual_order); |
| 311 | 317 |
| 312 // Reorder |line_item_chunks| in visual order. | 318 // Reorder |line_item_chunks| in visual order. |
| 313 Vector<LineItemChunk, 32> line_item_chunks_in_visual_order( | 319 Vector<LineItemChunk, 32> line_item_chunks_in_visual_order( |
| 314 line_item_chunks->size()); | 320 line_item_chunks->size()); |
| 315 for (unsigned visual_index = 0; visual_index < indices_in_visual_order.size(); | 321 for (unsigned visual_index = 0; visual_index < indices_in_visual_order.size(); |
| 316 visual_index++) { | 322 visual_index++) { |
| 317 unsigned logical_index = indices_in_visual_order[visual_index]; | 323 unsigned logical_index = indices_in_visual_order[visual_index]; |
| 318 line_item_chunks_in_visual_order[visual_index] = | 324 line_item_chunks_in_visual_order[visual_index] = |
| 319 (*line_item_chunks)[logical_index]; | 325 (*line_item_chunks)[logical_index]; |
| 320 } | 326 } |
| 327 |
| 328 // Keep Open before Close in the visual order. |
| 329 HashMap<LayoutObject*, unsigned> first_index; |
| 330 for (unsigned i = 0; i < line_item_chunks_in_visual_order.size(); i++) { |
| 331 LineItemChunk& chunk = line_item_chunks_in_visual_order[i]; |
| 332 const NGLayoutInlineItem& item = items[chunk.index]; |
| 333 if (item.Type() != NGLayoutInlineItem::kOpenTag && |
| 334 item.Type() != NGLayoutInlineItem::kCloseTag) { |
| 335 continue; |
| 336 } |
| 337 auto result = first_index.insert(item.GetLayoutObject(), i); |
| 338 if (!result.is_new_entry && item.Type() == NGLayoutInlineItem::kOpenTag) { |
| 339 std::swap(line_item_chunks_in_visual_order[i], |
| 340 line_item_chunks_in_visual_order[result.stored_value->value]); |
| 341 } |
| 342 } |
| 343 |
| 321 line_item_chunks->Swap(line_item_chunks_in_visual_order); | 344 line_item_chunks->Swap(line_item_chunks_in_visual_order); |
| 322 } | 345 } |
| 323 | 346 |
| 324 // TODO(glebl): Add the support of clearance for inline floats. | 347 // TODO(glebl): Add the support of clearance for inline floats. |
| 325 void NGInlineLayoutAlgorithm::LayoutAndPositionFloat( | 348 void NGInlineLayoutAlgorithm::LayoutAndPositionFloat( |
| 326 LayoutUnit end_position, | 349 LayoutUnit end_position, |
| 327 LayoutObject* layout_object) { | 350 LayoutObject* layout_object) { |
| 328 NGBlockNode* node = new NGBlockNode(layout_object); | 351 NGBlockNode* node = new NGBlockNode(layout_object); |
| 329 | 352 |
| 330 RefPtr<NGConstraintSpace> float_space = | 353 RefPtr<NGConstraintSpace> float_space = |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 376 // https://drafts.csswg.org/css2/visudet.html#strut | 399 // https://drafts.csswg.org/css2/visudet.html#strut |
| 377 const ComputedStyle& line_style = LineStyle(); | 400 const ComputedStyle& line_style = LineStyle(); |
| 378 NGLineHeightMetrics line_metrics(line_style, baseline_type_); | 401 NGLineHeightMetrics line_metrics(line_style, baseline_type_); |
| 379 NGLineHeightMetrics line_metrics_with_leading = line_metrics; | 402 NGLineHeightMetrics line_metrics_with_leading = line_metrics; |
| 380 line_metrics_with_leading.AddLeading(line_style.ComputedLineHeightAsFixed()); | 403 line_metrics_with_leading.AddLeading(line_style.ComputedLineHeightAsFixed()); |
| 381 NGLineBoxFragmentBuilder line_box(Node(), line_metrics_with_leading); | 404 NGLineBoxFragmentBuilder line_box(Node(), line_metrics_with_leading); |
| 382 | 405 |
| 383 // Compute heights of all inline items by placing the dominant baseline at 0. | 406 // Compute heights of all inline items by placing the dominant baseline at 0. |
| 384 // The baseline is adjusted after the height of the line box is computed. | 407 // The baseline is adjusted after the height of the line box is computed. |
| 385 NGTextFragmentBuilder text_builder(Node()); | 408 NGTextFragmentBuilder text_builder(Node()); |
| 409 NGInlineBoxState* box = OnBeginPlaceItems(); |
| 386 LayoutUnit inline_size; | 410 LayoutUnit inline_size; |
| 387 for (const auto& line_item_chunk : line_item_chunks) { | 411 for (const auto& line_item_chunk : line_item_chunks) { |
| 388 const NGLayoutInlineItem& item = items[line_item_chunk.index]; | 412 const NGLayoutInlineItem& item = items[line_item_chunk.index]; |
| 389 // Skip bidi controls. | 413 LayoutUnit line_top; |
| 390 if (!item.GetLayoutObject()) | |
| 391 continue; | |
| 392 | |
| 393 LayoutUnit block_start; | |
| 394 if (item.Type() == NGLayoutInlineItem::kText) { | 414 if (item.Type() == NGLayoutInlineItem::kText) { |
| 395 DCHECK(item.GetLayoutObject()->IsText()); | 415 DCHECK(item.GetLayoutObject()->IsText()); |
| 396 const ComputedStyle* style = item.Style(); | 416 if (box->text_metrics.IsEmpty()) |
| 397 // The direction of a fragment is the CSS direction to resolve logical | 417 box->ComputeTextMetrics(item, baseline_type_); |
| 398 // properties, not the resolved bidi direction. | 418 line_top = box->text_top; |
| 399 text_builder.SetDirection(style->Direction()) | 419 text_builder.SetSize( |
| 400 .SetInlineSize(line_item_chunk.inline_size); | 420 {line_item_chunk.inline_size, box->text_metrics.LineHeight()}); |
| 401 | |
| 402 // |InlineTextBoxPainter| sets the baseline at |top + | |
| 403 // ascent-of-primary-font|. Compute |top| to match. | |
| 404 NGLineHeightMetrics metrics(*style, baseline_type_); | |
| 405 block_start = -metrics.ascent; | |
| 406 metrics.AddLeading(style->ComputedLineHeightAsFixed()); | |
| 407 text_builder.SetBlockSize(metrics.LineHeight()); | |
| 408 line_box.UniteMetrics(metrics); | |
| 409 | |
| 410 // Take all used fonts into account if 'line-height: normal'. | 421 // Take all used fonts into account if 'line-height: normal'. |
| 411 if (style->LineHeight().IsNegative()) | 422 if (box->include_used_fonts) |
| 412 AccumulateUsedFonts(item, line_item_chunk, &line_box); | 423 AccumulateUsedFonts(item, line_item_chunk, &line_box); |
| 424 } else if (item.Type() == NGLayoutInlineItem::kOpenTag) { |
| 425 box = OnOpenTag(item, &line_box, &text_builder); |
| 426 continue; |
| 427 } else if (item.Type() == NGLayoutInlineItem::kCloseTag) { |
| 428 box = OnCloseTag(item, &line_box, box); |
| 429 continue; |
| 413 } else if (item.Type() == NGLayoutInlineItem::kAtomicInline) { | 430 } else if (item.Type() == NGLayoutInlineItem::kAtomicInline) { |
| 414 block_start = PlaceAtomicInline(item, &line_box, &text_builder); | 431 line_top = PlaceAtomicInline(item, &line_box, &text_builder); |
| 415 } else if (item.Type() == NGLayoutInlineItem::kOutOfFlowPositioned) { | 432 } else if (item.Type() == NGLayoutInlineItem::kOutOfFlowPositioned) { |
| 416 // TODO(layout-dev): Report the correct static position for the out of | 433 // TODO(layout-dev): Report the correct static position for the out of |
| 417 // flow descendant. We can't do this here yet as it doesn't know the | 434 // flow descendant. We can't do this here yet as it doesn't know the |
| 418 // size of the line box. | 435 // size of the line box. |
| 419 container_builder_.AddOutOfFlowDescendant( | 436 container_builder_.AddOutOfFlowDescendant( |
| 420 // Absolute positioning blockifies the box's display type. | 437 // Absolute positioning blockifies the box's display type. |
| 421 // https://drafts.csswg.org/css-display/#transformations | 438 // https://drafts.csswg.org/css-display/#transformations |
| 422 new NGBlockNode(item.GetLayoutObject()), | 439 new NGBlockNode(item.GetLayoutObject()), |
| 423 NGStaticPosition::Create(ConstraintSpace().WritingMode(), | 440 NGStaticPosition::Create(ConstraintSpace().WritingMode(), |
| 424 ConstraintSpace().Direction(), | 441 ConstraintSpace().Direction(), |
| 425 NGPhysicalOffset())); | 442 NGPhysicalOffset())); |
| 426 continue; | 443 continue; |
| 427 } else { | 444 } else { |
| 428 continue; | 445 continue; |
| 429 } | 446 } |
| 430 | 447 |
| 431 RefPtr<NGPhysicalTextFragment> text_fragment = text_builder.ToTextFragment( | 448 RefPtr<NGPhysicalTextFragment> text_fragment = text_builder.ToTextFragment( |
| 432 line_item_chunk.index, line_item_chunk.start_offset, | 449 line_item_chunk.index, line_item_chunk.start_offset, |
| 433 line_item_chunk.end_offset); | 450 line_item_chunk.end_offset); |
| 434 | 451 |
| 435 NGLogicalOffset logical_offset( | 452 NGLogicalOffset logical_offset( |
| 436 inline_size + current_opportunity_.InlineStartOffset() - | 453 inline_size + current_opportunity_.InlineStartOffset() - |
| 437 ConstraintSpace().BfcOffset().inline_offset, | 454 ConstraintSpace().BfcOffset().inline_offset, |
| 438 block_start); | 455 line_top); |
| 439 line_box.AddChild(std::move(text_fragment), logical_offset); | 456 line_box.AddChild(std::move(text_fragment), logical_offset); |
| 440 inline_size += line_item_chunk.inline_size; | 457 inline_size += line_item_chunk.inline_size; |
| 441 } | 458 } |
| 442 | 459 |
| 443 if (line_box.Children().IsEmpty()) { | 460 if (line_box.Children().IsEmpty()) { |
| 444 return true; // The line was empty. | 461 return true; // The line was empty. |
| 445 } | 462 } |
| 446 | 463 |
| 464 OnEndPlaceItems(&line_box); |
| 465 |
| 447 // The baselines are always placed at pixel boundaries. Not doing so results | 466 // The baselines are always placed at pixel boundaries. Not doing so results |
| 448 // in incorrect layout of text decorations, most notably underlines. | 467 // in incorrect layout of text decorations, most notably underlines. |
| 449 LayoutUnit baseline = content_size_ + line_box.Metrics().ascent; | 468 LayoutUnit baseline = content_size_ + line_box.Metrics().ascent; |
| 450 baseline = LayoutUnit(baseline.Round()); | 469 baseline = LayoutUnit(baseline.Round()); |
| 451 | 470 |
| 452 // Check if the line fits into the constraint space in block direction. | 471 // Check if the line fits into the constraint space in block direction. |
| 453 LayoutUnit line_bottom = baseline + line_box.Metrics().descent; | 472 LayoutUnit line_bottom = baseline + line_box.Metrics().descent; |
| 454 if (!container_builder_.Children().IsEmpty() && | 473 if (!container_builder_.Children().IsEmpty() && |
| 455 ConstraintSpace().AvailableSize().block_size != NGSizeIndefinite && | 474 ConstraintSpace().AvailableSize().block_size != NGSizeIndefinite && |
| 456 line_bottom > ConstraintSpace().AvailableSize().block_size) { | 475 line_bottom > ConstraintSpace().AvailableSize().block_size) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 473 line_box.MoveChildrenInBlockDirection(baseline); | 492 line_box.MoveChildrenInBlockDirection(baseline); |
| 474 line_box.SetInlineSize(inline_size); | 493 line_box.SetInlineSize(inline_size); |
| 475 container_builder_.AddChild(line_box.ToLineBoxFragment(), | 494 container_builder_.AddChild(line_box.ToLineBoxFragment(), |
| 476 {LayoutUnit(), baseline - line_metrics.ascent}); | 495 {LayoutUnit(), baseline - line_metrics.ascent}); |
| 477 | 496 |
| 478 max_inline_size_ = std::max(max_inline_size_, inline_size); | 497 max_inline_size_ = std::max(max_inline_size_, inline_size); |
| 479 content_size_ = line_bottom; | 498 content_size_ = line_bottom; |
| 480 return true; | 499 return true; |
| 481 } | 500 } |
| 482 | 501 |
| 502 // Initialize the box state stack for a new line. |
| 503 // @return The initial box state for the line. |
| 504 NGInlineBoxState* NGInlineLayoutAlgorithm::OnBeginPlaceItems() { |
| 505 if (box_states_.IsEmpty()) { |
| 506 // For the first line, push a box state for the line itself. |
| 507 box_states_.Resize(1); |
| 508 NGInlineBoxState* box = &box_states_.back(); |
| 509 box->fragment_start = 0; |
| 510 box->style = &LineStyle(); |
| 511 return box; |
| 512 } |
| 513 |
| 514 // For the following lines, clear states that are not shared across lines. |
| 515 for (auto& box : box_states_) { |
| 516 box.fragment_start = 0; |
| 517 box.metrics = NGLineHeightMetrics(); |
| 518 DCHECK(box.pending_descendants.IsEmpty()); |
| 519 } |
| 520 return &box_states_.back(); |
| 521 } |
| 522 |
| 523 // Push a box state stack. |
| 524 NGInlineBoxState* NGInlineLayoutAlgorithm::OnOpenTag( |
| 525 const NGLayoutInlineItem& item, |
| 526 NGLineBoxFragmentBuilder* line_box, |
| 527 NGTextFragmentBuilder* text_builder) { |
| 528 box_states_.Resize(box_states_.size() + 1); |
| 529 NGInlineBoxState* box = &box_states_.back(); |
| 530 box->fragment_start = line_box->Children().size(); |
| 531 box->style = item.Style(); |
| 532 text_builder->SetDirection(box->style->Direction()); |
| 533 return box; |
| 534 } |
| 535 |
| 536 // Pop a box state stack. |
| 537 NGInlineBoxState* NGInlineLayoutAlgorithm::OnCloseTag( |
| 538 const NGLayoutInlineItem& item, |
| 539 NGLineBoxFragmentBuilder* line_box, |
| 540 NGInlineBoxState* box) { |
| 541 EndBoxState(box, line_box); |
| 542 // TODO(kojii): When the algorithm restarts from a break token, the stack may |
| 543 // underflow. We need either synthesize a missing box state, or push all |
| 544 // parents on initialize. |
| 545 box_states_.pop_back(); |
| 546 return &box_states_.back(); |
| 547 } |
| 548 |
| 549 // Compute all the pending positioning at the end of a line. |
| 550 void NGInlineLayoutAlgorithm::OnEndPlaceItems( |
| 551 NGLineBoxFragmentBuilder* line_box) { |
| 552 for (auto it = box_states_.rbegin(); it != box_states_.rend(); ++it) { |
| 553 NGInlineBoxState* box = &(*it); |
| 554 EndBoxState(box, line_box); |
| 555 } |
| 556 line_box->UniteMetrics(box_states_.front().metrics); |
| 557 } |
| 558 |
| 559 // End of a box state, either explicitly by close tag, or implicitly at the end |
| 560 // of a line. |
| 561 void NGInlineLayoutAlgorithm::EndBoxState(NGInlineBoxState* box, |
| 562 NGLineBoxFragmentBuilder* line_box) { |
| 563 ApplyBaselineShift(box, line_box); |
| 564 |
| 565 // Unite the metrics to the parent box. |
| 566 if (box != box_states_.begin()) { |
| 567 box[-1].metrics.Unite(box->metrics); |
| 568 } |
| 569 } |
| 570 |
| 571 // Compute vertical position for the 'vertical-align' property. |
| 572 // The timing to apply varies by values; some values apply at the layout of |
| 573 // the box was computed. Other values apply when the layout of the parent or |
| 574 // the line box was computed. |
| 575 // https://www.w3.org/TR/CSS22/visudet.html#propdef-vertical-align |
| 576 // https://www.w3.org/TR/css-inline-3/#propdef-vertical-align |
| 577 void NGInlineLayoutAlgorithm::ApplyBaselineShift( |
| 578 NGInlineBoxState* box, |
| 579 NGLineBoxFragmentBuilder* line_box) { |
| 580 // Compute descendants that depend on the layout size of this box if any. |
| 581 LayoutUnit baseline_shift; |
| 582 if (!box->pending_descendants.IsEmpty()) { |
| 583 for (const auto& child : box->pending_descendants) { |
| 584 switch (child.vertical_align) { |
| 585 case EVerticalAlign::kTextTop: |
| 586 case EVerticalAlign::kTop: |
| 587 baseline_shift = child.metrics.ascent - box->metrics.ascent; |
| 588 break; |
| 589 case EVerticalAlign::kTextBottom: |
| 590 case EVerticalAlign::kBottom: |
| 591 baseline_shift = box->metrics.descent - child.metrics.descent; |
| 592 break; |
| 593 default: |
| 594 NOTREACHED(); |
| 595 continue; |
| 596 } |
| 597 line_box->MoveChildrenInBlockDirection( |
| 598 baseline_shift, child.fragment_start, child.fragment_end); |
| 599 } |
| 600 box->pending_descendants.Clear(); |
| 601 } |
| 602 |
| 603 const ComputedStyle& style = *box->style; |
| 604 EVerticalAlign vertical_align = style.VerticalAlign(); |
| 605 if (vertical_align == EVerticalAlign::kBaseline) |
| 606 return; |
| 607 |
| 608 // 'vertical-align' aplies only to inline-level elements. |
| 609 if (box == box_states_.begin()) |
| 610 return; |
| 611 |
| 612 // Check if there are any fragments to move. |
| 613 unsigned fragment_end = line_box->Children().size(); |
| 614 if (box->fragment_start == fragment_end) |
| 615 return; |
| 616 |
| 617 switch (vertical_align) { |
| 618 case EVerticalAlign::kSub: |
| 619 baseline_shift = style.ComputedFontSizeAsFixed() / 5 + 1; |
| 620 break; |
| 621 case EVerticalAlign::kSuper: |
| 622 baseline_shift = -(style.ComputedFontSizeAsFixed() / 3 + 1); |
| 623 break; |
| 624 case EVerticalAlign::kLength: { |
| 625 // 'Percentages: refer to the 'line-height' of the element itself'. |
| 626 // https://www.w3.org/TR/CSS22/visudet.html#propdef-vertical-align |
| 627 const Length& length = style.GetVerticalAlignLength(); |
| 628 LayoutUnit line_height = length.IsPercentOrCalc() |
| 629 ? style.ComputedLineHeightAsFixed() |
| 630 : box->text_metrics.LineHeight(); |
| 631 baseline_shift = -ValueForLength(length, line_height); |
| 632 break; |
| 633 } |
| 634 case EVerticalAlign::kMiddle: |
| 635 baseline_shift = (box->metrics.ascent - box->metrics.descent) / 2; |
| 636 if (const SimpleFontData* font_data = style.GetFont().PrimaryFont()) { |
| 637 baseline_shift -= LayoutUnit::FromFloatRound( |
| 638 font_data->GetFontMetrics().XHeight() / 2); |
| 639 } |
| 640 break; |
| 641 case EVerticalAlign::kBaselineMiddle: |
| 642 baseline_shift = (box->metrics.ascent - box->metrics.descent) / 2; |
| 643 break; |
| 644 case EVerticalAlign::kTop: |
| 645 case EVerticalAlign::kBottom: |
| 646 // 'top' and 'bottom' require the layout size of the line box. |
| 647 box_states_.front().pending_descendants.push_back(NGPendingPositions{ |
| 648 box->fragment_start, fragment_end, box->metrics, vertical_align}); |
| 649 return; |
| 650 default: |
| 651 // Other values require the layout size of the parent box. |
| 652 SECURITY_CHECK(box != box_states_.begin()); |
| 653 box[-1].pending_descendants.push_back(NGPendingPositions{ |
| 654 box->fragment_start, fragment_end, box->metrics, vertical_align}); |
| 655 return; |
| 656 } |
| 657 box->metrics.Move(baseline_shift); |
| 658 line_box->MoveChildrenInBlockDirection(baseline_shift, box->fragment_start, |
| 659 fragment_end); |
| 660 } |
| 661 |
| 483 void NGInlineLayoutAlgorithm::AccumulateUsedFonts( | 662 void NGInlineLayoutAlgorithm::AccumulateUsedFonts( |
| 484 const NGLayoutInlineItem& item, | 663 const NGLayoutInlineItem& item, |
| 485 const LineItemChunk& line_item_chunk, | 664 const LineItemChunk& line_item_chunk, |
| 486 NGLineBoxFragmentBuilder* line_box) { | 665 NGLineBoxFragmentBuilder* line_box) { |
| 487 HashSet<const SimpleFontData*> fallback_fonts; | 666 HashSet<const SimpleFontData*> fallback_fonts; |
| 488 item.GetFallbackFonts(&fallback_fonts, line_item_chunk.start_offset, | 667 item.GetFallbackFonts(&fallback_fonts, line_item_chunk.start_offset, |
| 489 line_item_chunk.end_offset); | 668 line_item_chunk.end_offset); |
| 490 for (const auto& fallback_font : fallback_fonts) { | 669 for (const auto& fallback_font : fallback_fonts) { |
| 491 NGLineHeightMetrics metrics(fallback_font->GetFontMetrics(), | 670 NGLineHeightMetrics metrics(fallback_font->GetFontMetrics(), |
| 492 baseline_type_); | 671 baseline_type_); |
| 493 metrics.AddLeading(fallback_font->GetFontMetrics().FixedLineSpacing()); | 672 metrics.AddLeading(fallback_font->GetFontMetrics().FixedLineSpacing()); |
| 494 line_box->UniteMetrics(metrics); | 673 line_box->UniteMetrics(metrics); |
| 495 } | 674 } |
| 496 } | 675 } |
| 497 | 676 |
| 498 LayoutUnit NGInlineLayoutAlgorithm::PlaceAtomicInline( | 677 LayoutUnit NGInlineLayoutAlgorithm::PlaceAtomicInline( |
| 499 const NGLayoutInlineItem& item, | 678 const NGLayoutInlineItem& item, |
| 500 NGLineBoxFragmentBuilder* line_box, | 679 NGLineBoxFragmentBuilder* line_box, |
| 501 NGTextFragmentBuilder* text_builder) { | 680 NGTextFragmentBuilder* text_builder) { |
| 502 NGBoxFragment fragment( | 681 NGBoxFragment fragment( |
| 503 ConstraintSpace().WritingMode(), | 682 ConstraintSpace().WritingMode(), |
| 504 ToNGPhysicalBoxFragment(LayoutItem(item)->PhysicalFragment().Get())); | 683 ToNGPhysicalBoxFragment(LayoutItem(item)->PhysicalFragment().Get())); |
| 505 // TODO(kojii): Margin and border in block progression not implemented yet. | 684 // TODO(kojii): Margin and border in block progression not implemented yet. |
| 506 LayoutUnit block_size = fragment.BlockSize(); | 685 LayoutUnit block_size = fragment.BlockSize(); |
| 507 | 686 |
| 508 // TODO(kojii): Try to eliminate the wrapping text fragment and use the | 687 // TODO(kojii): Try to eliminate the wrapping text fragment and use the |
| 509 // |fragment| directly. Currently |CopyFragmentDataToLayoutBlockFlow| | 688 // |fragment| directly. Currently |CopyFragmentDataToLayoutBlockFlow| |
| 510 // requires a text fragment. | 689 // requires a text fragment. |
| 511 text_builder->SetInlineSize(fragment.InlineSize()).SetBlockSize(block_size); | 690 text_builder->SetSize({fragment.InlineSize(), block_size}); |
| 512 | 691 |
| 513 // TODO(kojii): Add baseline position to NGPhysicalFragment. | 692 // TODO(kojii): Add baseline position to NGPhysicalFragment. |
| 514 LayoutBox* box = ToLayoutBox(item.GetLayoutObject()); | 693 LayoutBox* layout_box = ToLayoutBox(item.GetLayoutObject()); |
| 515 LineDirectionMode line_direction_mode = | 694 LineDirectionMode line_direction_mode = |
| 516 IsHorizontalWritingMode() ? LineDirectionMode::kHorizontalLine | 695 IsHorizontalWritingMode() ? LineDirectionMode::kHorizontalLine |
| 517 : LineDirectionMode::kVerticalLine; | 696 : LineDirectionMode::kVerticalLine; |
| 518 LayoutUnit baseline_offset(box->BaselinePosition( | 697 LayoutUnit baseline_offset(layout_box->BaselinePosition( |
| 519 baseline_type_, IsFirstLine(), line_direction_mode)); | 698 baseline_type_, IsFirstLine(), line_direction_mode)); |
| 520 line_box->UniteMetrics({baseline_offset, block_size - baseline_offset}); | 699 |
| 700 NGLineHeightMetrics metrics(baseline_offset, block_size - baseline_offset); |
| 701 box_states_.back().metrics.Unite(metrics); |
| 521 | 702 |
| 522 // TODO(kojii): Figure out what to do with OOF in NGLayoutResult. | 703 // TODO(kojii): Figure out what to do with OOF in NGLayoutResult. |
| 523 // Floats are ok because atomic inlines are BFC? | 704 // Floats are ok because atomic inlines are BFC? |
| 524 | 705 |
| 525 return -baseline_offset; | 706 return -metrics.ascent; |
| 526 } | 707 } |
| 527 | 708 |
| 528 void NGInlineLayoutAlgorithm::FindNextLayoutOpportunity() { | 709 void NGInlineLayoutAlgorithm::FindNextLayoutOpportunity() { |
| 529 NGLogicalOffset iter_offset = ConstraintSpace().BfcOffset(); | 710 NGLogicalOffset iter_offset = ConstraintSpace().BfcOffset(); |
| 530 iter_offset.block_offset += content_size_; | 711 iter_offset.block_offset += content_size_; |
| 531 auto* iter = MutableConstraintSpace()->LayoutOpportunityIterator(iter_offset); | 712 auto* iter = MutableConstraintSpace()->LayoutOpportunityIterator(iter_offset); |
| 532 NGLayoutOpportunity opportunity = iter->Next(); | 713 NGLayoutOpportunity opportunity = iter->Next(); |
| 533 if (!opportunity.IsEmpty()) | 714 if (!opportunity.IsEmpty()) |
| 534 current_opportunity_ = opportunity; | 715 current_opportunity_ = opportunity; |
| 535 } | 716 } |
| (...skipping 27 matching lines...) Expand all Loading... |
| 563 | 744 |
| 564 // max-content is the width without any line wrapping. | 745 // max-content is the width without any line wrapping. |
| 565 // TODO(kojii): Implement hard breaks (<br> etc.) to break. | 746 // TODO(kojii): Implement hard breaks (<br> etc.) to break. |
| 566 for (const auto& item : Node()->Items()) | 747 for (const auto& item : Node()->Items()) |
| 567 sizes.max_content += InlineSize(item); | 748 sizes.max_content += InlineSize(item); |
| 568 | 749 |
| 569 return sizes; | 750 return sizes; |
| 570 } | 751 } |
| 571 | 752 |
| 572 } // namespace blink | 753 } // namespace blink |
| OLD | NEW |