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/ng_line_builder.h" | 5 #include "core/layout/ng/ng_line_builder.h" |
6 | 6 |
7 #include "core/layout/BidiRun.h" | 7 #include "core/layout/BidiRun.h" |
8 #include "core/layout/LayoutBlockFlow.h" | 8 #include "core/layout/LayoutBlockFlow.h" |
9 #include "core/layout/line/LineInfo.h" | 9 #include "core/layout/line/LineInfo.h" |
10 #include "core/layout/line/RootInlineBox.h" | 10 #include "core/layout/line/RootInlineBox.h" |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
211 // estimation turned out to be different. | 211 // estimation turned out to be different. |
212 LayoutUnit estimated_baseline = | 212 LayoutUnit estimated_baseline = |
213 content_size_ + LayoutUnit(block_metrics.ascent_and_leading); | 213 content_size_ + LayoutUnit(block_metrics.ascent_and_leading); |
214 | 214 |
215 for (const auto& line_item_chunk : line_item_chunks) { | 215 for (const auto& line_item_chunk : line_item_chunks) { |
216 const NGLayoutInlineItem& item = items[line_item_chunk.index]; | 216 const NGLayoutInlineItem& item = items[line_item_chunk.index]; |
217 // Skip bidi controls. | 217 // Skip bidi controls. |
218 if (!item.GetLayoutObject()) | 218 if (!item.GetLayoutObject()) |
219 continue; | 219 continue; |
220 | 220 |
221 LayoutUnit top, height; | 221 LayoutUnit top; |
222 const ComputedStyle* style = item.Style(); | 222 const ComputedStyle* style = item.Style(); |
223 if (style) { | 223 if (style) { |
| 224 DCHECK(item.GetLayoutObject()->isText()); |
224 // |InlineTextBoxPainter| sets the baseline at |top + | 225 // |InlineTextBoxPainter| sets the baseline at |top + |
225 // ascent-of-primary-font|. Compute |top| to match. | 226 // ascent-of-primary-font|. Compute |top| to match. |
226 InlineItemMetrics metrics(*style, baseline_type_); | 227 InlineItemMetrics metrics(*style, baseline_type_); |
227 top = estimated_baseline - LayoutUnit(metrics.ascent); | 228 top = estimated_baseline - LayoutUnit(metrics.ascent); |
228 height = LayoutUnit(metrics.ascent + metrics.descent); | 229 LayoutUnit height = LayoutUnit(metrics.ascent + metrics.descent); |
229 line_box_data.UpdateMaxAscentAndDescent(metrics); | 230 line_box_data.UpdateMaxAscentAndDescent(metrics); |
230 | 231 |
231 // Take all used fonts into account if 'line-height: normal'. | 232 // Take all used fonts into account if 'line-height: normal'. |
232 if (style->lineHeight().isNegative()) | 233 if (style->lineHeight().isNegative()) |
233 AccumulateUsedFonts(item, line_item_chunk, &line_box_data); | 234 AccumulateUsedFonts(item, line_item_chunk, &line_box_data); |
| 235 |
| 236 // The direction of a fragment is the CSS direction to resolve logical |
| 237 // properties, not the resolved bidi direction. |
| 238 text_builder.SetDirection(style->direction()) |
| 239 .SetInlineSize(line_item_chunk.inline_size) |
| 240 .SetInlineOverflow(line_item_chunk.inline_size) |
| 241 .SetBlockSize(height) |
| 242 .SetBlockOverflow(height); |
234 } else { | 243 } else { |
235 LayoutObject* layout_object = item.GetLayoutObject(); | 244 LayoutObject* layout_object = item.GetLayoutObject(); |
236 if (layout_object->isOutOfFlowPositioned()) { | 245 if (layout_object->isOutOfFlowPositioned()) { |
237 if (containing_block_builder_) { | 246 if (containing_block_builder_) { |
238 // Absolute positioning blockifies the box's display type. | 247 // Absolute positioning blockifies the box's display type. |
239 // https://drafts.csswg.org/css-display/#transformations | 248 // https://drafts.csswg.org/css-display/#transformations |
240 containing_block_builder_->AddOutOfFlowChildCandidate( | 249 containing_block_builder_->AddOutOfFlowChildCandidate( |
241 new NGBlockNode(layout_object), | 250 new NGBlockNode(layout_object), |
242 NGLogicalOffset(line_box_data.inline_size, content_size_)); | 251 NGLogicalOffset(line_box_data.inline_size, content_size_)); |
243 } | 252 } |
244 continue; | 253 continue; |
245 } else if (layout_object->isFloating()) { | 254 } else if (layout_object->isFloating()) { |
246 // TODO(kojii): Implement float. | 255 // TODO(kojii): Implement float. |
247 DLOG(ERROR) << "Floats in inline not implemented yet."; | 256 DLOG(ERROR) << "Floats in inline not implemented yet."; |
248 // TODO(kojii): Temporarily clearNeedsLayout() for not to assert. | 257 // TODO(kojii): Temporarily clearNeedsLayout() for not to assert. |
249 layout_object->clearNeedsLayout(); | 258 layout_object->clearNeedsLayout(); |
250 continue; | 259 continue; |
251 } | 260 } |
252 DCHECK(layout_object->isAtomicInlineLevel()); | 261 top = PlaceAtomicInline(item, estimated_baseline, &line_box_data, |
253 // TODO(kojii): Implement atomic inline. | 262 &text_builder); |
254 style = layout_object->style(); | |
255 top = content_size_; | |
256 } | 263 } |
257 | 264 |
258 // The direction of a fragment is the CSS direction to resolve logical | |
259 // properties, not the resolved bidi direction. | |
260 text_builder.SetDirection(style->direction()) | |
261 .SetInlineSize(line_item_chunk.inline_size) | |
262 .SetInlineOverflow(line_item_chunk.inline_size) | |
263 .SetBlockSize(height) | |
264 .SetBlockOverflow(height); | |
265 RefPtr<NGPhysicalTextFragment> text_fragment = text_builder.ToTextFragment( | 265 RefPtr<NGPhysicalTextFragment> text_fragment = text_builder.ToTextFragment( |
266 line_item_chunk.index, line_item_chunk.start_offset, | 266 line_item_chunk.index, line_item_chunk.start_offset, |
267 line_item_chunk.end_offset); | 267 line_item_chunk.end_offset); |
268 fragments_.push_back(std::move(text_fragment)); | 268 fragments_.push_back(std::move(text_fragment)); |
269 | 269 |
270 NGLogicalOffset logical_offset( | 270 NGLogicalOffset logical_offset( |
271 line_box_data.inline_size + current_opportunity_.InlineStartOffset() - | 271 line_box_data.inline_size + current_opportunity_.InlineStartOffset() - |
272 ConstraintSpace().BfcOffset().inline_offset, | 272 ConstraintSpace().BfcOffset().inline_offset, |
273 top); | 273 top); |
274 offsets_.push_back(logical_offset); | 274 offsets_.push_back(logical_offset); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
345 HashSet<const SimpleFontData*> fallback_fonts; | 345 HashSet<const SimpleFontData*> fallback_fonts; |
346 item.GetFallbackFonts(&fallback_fonts, line_item_chunk.start_offset, | 346 item.GetFallbackFonts(&fallback_fonts, line_item_chunk.start_offset, |
347 line_item_chunk.end_offset); | 347 line_item_chunk.end_offset); |
348 for (const auto& fallback_font : fallback_fonts) { | 348 for (const auto& fallback_font : fallback_fonts) { |
349 InlineItemMetrics fallback_font_metrics(fallback_font->getFontMetrics(), | 349 InlineItemMetrics fallback_font_metrics(fallback_font->getFontMetrics(), |
350 baseline_type_); | 350 baseline_type_); |
351 line_box_data->UpdateMaxAscentAndDescent(fallback_font_metrics); | 351 line_box_data->UpdateMaxAscentAndDescent(fallback_font_metrics); |
352 } | 352 } |
353 } | 353 } |
354 | 354 |
| 355 LayoutUnit NGLineBuilder::PlaceAtomicInline(const NGLayoutInlineItem& item, |
| 356 LayoutUnit estimated_baseline, |
| 357 LineBoxData* line_box_data, |
| 358 NGFragmentBuilder* text_builder) { |
| 359 LayoutObject* layout_object = item.GetLayoutObject(); |
| 360 DCHECK(layout_object && layout_object->isAtomicInlineLevel()); |
| 361 const NGLayoutResult* layout_result = item.GetLayoutResult(); |
| 362 DCHECK(layout_result); |
| 363 RefPtr<NGPhysicalFragment> fragment = layout_result->PhysicalFragment(); |
| 364 bool is_horizontal_writing_mode = |
| 365 IsHorizontalWritingMode(ConstraintSpace().WritingMode()); |
| 366 LayoutUnit height; |
| 367 // TODO(kojii): Try to eliminate the text fragment and use the |fragment| |
| 368 // directly. Currently |CopyFragmentDataToLayoutBlockFlow| requires a text |
| 369 // fragment. |
| 370 // TODO(kojii): Margin and border in block progression not implemented yet. |
| 371 if (is_horizontal_writing_mode) { |
| 372 height = fragment->Height(); |
| 373 text_builder->SetInlineSize(fragment->Width()) |
| 374 .SetInlineOverflow(fragment->WidthOverflow()) |
| 375 .SetBlockSize(height) |
| 376 .SetBlockOverflow(fragment->HeightOverflow()); |
| 377 } else { |
| 378 height = fragment->Width(); |
| 379 text_builder->SetInlineSize(fragment->Height()) |
| 380 .SetInlineOverflow(fragment->HeightOverflow()) |
| 381 .SetBlockSize(height) |
| 382 .SetBlockOverflow(fragment->WidthOverflow()); |
| 383 } |
| 384 |
| 385 // TODO(kojii): Add baseline position to NGPhysicalFragment. |
| 386 LayoutBox* box = toLayoutBox(layout_object); |
| 387 LineDirectionMode line_direction_mode = |
| 388 is_horizontal_writing_mode ? LineDirectionMode::HorizontalLine |
| 389 : LineDirectionMode::VerticalLine; |
| 390 bool is_first_line = line_box_data_list_.size() == 1; |
| 391 int baseline_offset = |
| 392 box->baselinePosition(baseline_type_, is_first_line, line_direction_mode); |
| 393 LayoutUnit top = estimated_baseline - baseline_offset; |
| 394 |
| 395 line_box_data->max_ascent_and_leading = |
| 396 std::max<float>(baseline_offset, line_box_data->max_ascent_and_leading); |
| 397 line_box_data->max_descent_and_leading = std::max<float>( |
| 398 height - baseline_offset, line_box_data->max_descent_and_leading); |
| 399 |
| 400 return top; |
| 401 } |
| 402 |
355 void NGLineBuilder::FindNextLayoutOpportunity() { | 403 void NGLineBuilder::FindNextLayoutOpportunity() { |
356 NGLogicalOffset iter_offset = constraint_space_->BfcOffset(); | 404 NGLogicalOffset iter_offset = constraint_space_->BfcOffset(); |
357 iter_offset.block_offset += content_size_; | 405 iter_offset.block_offset += content_size_; |
358 auto* iter = constraint_space_->LayoutOpportunityIterator(iter_offset); | 406 auto* iter = constraint_space_->LayoutOpportunityIterator(iter_offset); |
359 NGLayoutOpportunity opportunity = iter->Next(); | 407 NGLayoutOpportunity opportunity = iter->Next(); |
360 if (!opportunity.IsEmpty()) | 408 if (!opportunity.IsEmpty()) |
361 current_opportunity_ = opportunity; | 409 current_opportunity_ = opportunity; |
362 } | 410 } |
363 | 411 |
364 RefPtr<NGLayoutResult> NGLineBuilder::CreateFragments() { | 412 RefPtr<NGLayoutResult> NGLineBuilder::CreateFragments() { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
410 if (layout_object->isText()) { | 458 if (layout_object->isText()) { |
411 unsigned text_offset = text_offsets[text_fragment->ItemIndex()]; | 459 unsigned text_offset = text_offsets[text_fragment->ItemIndex()]; |
412 run = new BidiRun(text_fragment->StartOffset() - text_offset, | 460 run = new BidiRun(text_fragment->StartOffset() - text_offset, |
413 text_fragment->EndOffset() - text_offset, | 461 text_fragment->EndOffset() - text_offset, |
414 item.BidiLevel(), LineLayoutItem(layout_object)); | 462 item.BidiLevel(), LineLayoutItem(layout_object)); |
415 layout_object->clearNeedsLayout(); | 463 layout_object->clearNeedsLayout(); |
416 } else { | 464 } else { |
417 DCHECK(layout_object->isAtomicInlineLevel()); | 465 DCHECK(layout_object->isAtomicInlineLevel()); |
418 run = | 466 run = |
419 new BidiRun(0, 1, item.BidiLevel(), LineLayoutItem(layout_object)); | 467 new BidiRun(0, 1, item.BidiLevel(), LineLayoutItem(layout_object)); |
420 // TODO(kojii): Temporarily clearNeedsLayout() for not to assert. | |
421 layout_object->clearNeedsLayout(); | |
422 } | 468 } |
423 bidi_runs.addRun(run); | 469 bidi_runs.addRun(run); |
424 fragments_for_bidi_runs.push_back(text_fragment); | 470 fragments_for_bidi_runs.push_back(text_fragment); |
425 } | 471 } |
426 // TODO(kojii): bidi needs to find the logical last run. | 472 // TODO(kojii): bidi needs to find the logical last run. |
427 bidi_runs.setLogicallyLastRun(bidi_runs.lastRun()); | 473 bidi_runs.setLogicallyLastRun(bidi_runs.lastRun()); |
428 | 474 |
429 // Create a RootInlineBox from BidiRunList. InlineBoxes created for the | 475 // Create a RootInlineBox from BidiRunList. InlineBoxes created for the |
430 // RootInlineBox are set to Bidirun::m_box. | 476 // RootInlineBox are set to Bidirun::m_box. |
431 line_info.setEmpty(false); | 477 line_info.setEmpty(false); |
432 // TODO(kojii): Implement setFirstLine, LastLine, etc. | 478 // TODO(kojii): Implement setFirstLine, LastLine, etc. |
433 RootInlineBox* line_box = block->constructLine(bidi_runs, line_info); | 479 RootInlineBox* line_box = block->constructLine(bidi_runs, line_info); |
434 | 480 |
435 // Copy fragments data to InlineBoxes. | 481 // Copy fragments data to InlineBoxes. |
436 DCHECK_EQ(fragments_for_bidi_runs.size(), bidi_runs.runCount()); | 482 DCHECK_EQ(fragments_for_bidi_runs.size(), bidi_runs.runCount()); |
437 BidiRun* run = bidi_runs.firstRun(); | 483 BidiRun* run = bidi_runs.firstRun(); |
438 for (auto* physical_fragment : fragments_for_bidi_runs) { | 484 for (auto* physical_fragment : fragments_for_bidi_runs) { |
439 DCHECK(run); | 485 DCHECK(run); |
440 NGTextFragment fragment(ConstraintSpace().WritingMode(), | 486 NGTextFragment fragment(ConstraintSpace().WritingMode(), |
441 toNGPhysicalTextFragment(physical_fragment)); | 487 toNGPhysicalTextFragment(physical_fragment)); |
442 InlineBox* inline_box = run->m_box; | 488 InlineBox* inline_box = run->m_box; |
443 inline_box->setLogicalWidth(fragment.InlineSize()); | 489 inline_box->setLogicalWidth(fragment.InlineSize()); |
444 inline_box->setLogicalLeft(fragment.InlineOffset()); | 490 inline_box->setLogicalLeft(fragment.InlineOffset()); |
445 inline_box->setLogicalTop(fragment.BlockOffset()); | 491 inline_box->setLogicalTop(fragment.BlockOffset()); |
| 492 if (inline_box->getLineLayoutItem().isBox()) { |
| 493 LineLayoutBox box(inline_box->getLineLayoutItem()); |
| 494 box.setLocation(inline_box->location()); |
| 495 } |
446 run = run->next(); | 496 run = run->next(); |
447 } | 497 } |
448 DCHECK(!run); | 498 DCHECK(!run); |
449 | 499 |
450 // Copy LineBoxData to RootInlineBox. | 500 // Copy LineBoxData to RootInlineBox. |
451 line_box->setLogicalWidth(line_box_data.inline_size); | 501 line_box->setLogicalWidth(line_box_data.inline_size); |
| 502 line_box->setLogicalTop(line_box_data.top_with_leading); |
452 LayoutUnit baseline_position = | 503 LayoutUnit baseline_position = |
453 line_box_data.top_with_leading + | 504 line_box_data.top_with_leading + |
454 LayoutUnit(line_box_data.max_ascent_and_leading); | 505 LayoutUnit(line_box_data.max_ascent_and_leading); |
455 line_box->setLineTopBottomPositions( | 506 line_box->setLineTopBottomPositions( |
456 baseline_position - LayoutUnit(line_box_data.max_ascent), | 507 baseline_position - LayoutUnit(line_box_data.max_ascent), |
457 baseline_position + LayoutUnit(line_box_data.max_descent), | 508 baseline_position + LayoutUnit(line_box_data.max_descent), |
458 line_box_data.top_with_leading, | 509 line_box_data.top_with_leading, |
459 baseline_position + LayoutUnit(line_box_data.max_descent_and_leading)); | 510 baseline_position + LayoutUnit(line_box_data.max_descent_and_leading)); |
460 | 511 |
461 bidi_runs.deleteRuns(); | 512 bidi_runs.deleteRuns(); |
462 fragments_for_bidi_runs.clear(); | 513 fragments_for_bidi_runs.clear(); |
463 } | 514 } |
464 } | 515 } |
465 } // namespace blink | 516 } // namespace blink |
OLD | NEW |