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

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

Issue 2931563002: [LayoutNG] Implement 'text-align-last' (Closed)
Patch Set: Rebase Created 3 years, 6 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
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_line_breaker.h" 5 #include "core/layout/ng/inline/ng_line_breaker.h"
6 6
7 #include "core/layout/ng/inline/ng_inline_break_token.h" 7 #include "core/layout/ng/inline/ng_inline_break_token.h"
8 #include "core/layout/ng/inline/ng_inline_layout_algorithm.h" 8 #include "core/layout/ng/inline/ng_inline_layout_algorithm.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_text_fragment.h" 10 #include "core/layout/ng/inline/ng_text_fragment.h"
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
64 offset_(0), 64 offset_(0),
65 break_iterator_(node.Text()), 65 break_iterator_(node.Text()),
66 shaper_(node.Text().Characters16(), node.Text().length()) { 66 shaper_(node.Text().Characters16(), node.Text().length()) {
67 if (break_token) { 67 if (break_token) {
68 item_index_ = break_token->ItemIndex(); 68 item_index_ = break_token->ItemIndex();
69 offset_ = break_token->TextOffset(); 69 offset_ = break_token->TextOffset();
70 node.AssertOffset(item_index_, offset_); 70 node.AssertOffset(item_index_, offset_);
71 } 71 }
72 } 72 }
73 73
74 void NGLineBreaker::NextLine(NGInlineItemResults* item_results, 74 bool NGLineBreaker::NextLine(NGLineInfo* line_info,
75 NGInlineLayoutAlgorithm* algorithm) { 75 NGInlineLayoutAlgorithm* algorithm) {
76 BreakLine(item_results, algorithm); 76 BreakLine(line_info, algorithm);
77 77
78 // TODO(kojii): When editing, or caret is enabled, trailing spaces at wrap 78 // TODO(kojii): When editing, or caret is enabled, trailing spaces at wrap
79 // point should not be removed. For other cases, we can a) remove, b) leave 79 // point should not be removed. For other cases, we can a) remove, b) leave
80 // characters without glyphs, or c) leave both characters and glyphs without 80 // characters without glyphs, or c) leave both characters and glyphs without
81 // measuring. Need to decide which one works the best. 81 // measuring. Need to decide which one works the best.
82 SkipCollapsibleWhitespaces(); 82 SkipCollapsibleWhitespaces();
83
84 return !line_info->Results().IsEmpty();
83 } 85 }
84 86
85 void NGLineBreaker::BreakLine(NGInlineItemResults* item_results, 87 void NGLineBreaker::BreakLine(NGLineInfo* line_info,
86 NGInlineLayoutAlgorithm* algorithm) { 88 NGInlineLayoutAlgorithm* algorithm) {
87 DCHECK(item_results->IsEmpty()); 89 NGInlineItemResults* item_results = &line_info->Results();
90 item_results->clear();
88 const Vector<NGInlineItem>& items = node_.Items(); 91 const Vector<NGInlineItem>& items = node_.Items();
89 const ComputedStyle& style = node_.Style(); 92 line_info->SetLineStyle(node_, !item_index_ && !offset_);
90 UpdateBreakIterator(style); 93 UpdateBreakIterator(line_info->LineStyle());
91 available_width_ = algorithm->AvailableWidth(); 94 available_width_ = algorithm->AvailableWidth();
92 position_ = LayoutUnit(0); 95 position_ = LayoutUnit(0);
93 LineBreakState state = LineBreakState::kNotBreakable; 96 LineBreakState state = LineBreakState::kNotBreakable;
94 97
95 while (item_index_ < items.size()) { 98 while (item_index_ < items.size()) {
96 // CloseTag prohibits to break before. 99 // CloseTag prohibits to break before.
97 const NGInlineItem& item = items[item_index_]; 100 const NGInlineItem& item = items[item_index_];
98 if (item.Type() == NGInlineItem::kCloseTag) { 101 if (item.Type() == NGInlineItem::kCloseTag) {
99 item_results->push_back( 102 item_results->push_back(
100 NGInlineItemResult(item_index_, offset_, item.EndOffset())); 103 NGInlineItemResult(item_index_, offset_, item.EndOffset()));
101 HandleCloseTag(item, &item_results->back()); 104 HandleCloseTag(item, &item_results->back());
102 continue; 105 continue;
103 } 106 }
104 107
105 if (state == LineBreakState::kBreakAfterTrailings) 108 if (state == LineBreakState::kBreakAfterTrailings) {
109 line_info->SetIsLastLine(false);
106 return; 110 return;
111 }
107 if (state == LineBreakState::kIsBreakable && position_ > available_width_) 112 if (state == LineBreakState::kIsBreakable && position_ > available_width_)
108 return HandleOverflow(item_results); 113 return HandleOverflow(line_info);
109 114
110 item_results->push_back( 115 item_results->push_back(
111 NGInlineItemResult(item_index_, offset_, item.EndOffset())); 116 NGInlineItemResult(item_index_, offset_, item.EndOffset()));
112 NGInlineItemResult* item_result = &item_results->back(); 117 NGInlineItemResult* item_result = &item_results->back();
113 if (item.Type() == NGInlineItem::kText) { 118 if (item.Type() == NGInlineItem::kText) {
114 state = HandleText(item, item_result); 119 state = HandleText(item, item_result);
115 } else if (item.Type() == NGInlineItem::kAtomicInline) { 120 } else if (item.Type() == NGInlineItem::kAtomicInline) {
116 state = HandleAtomicInline(item, item_result); 121 state = HandleAtomicInline(item, item_result);
117 } else if (item.Type() == NGInlineItem::kControl) { 122 } else if (item.Type() == NGInlineItem::kControl) {
118 state = HandleControlItem(item, item_result); 123 state = HandleControlItem(item, item_result);
119 if (state == LineBreakState::kForcedBreak) 124 if (state == LineBreakState::kForcedBreak) {
125 line_info->SetIsLastLine(true);
120 return; 126 return;
127 }
121 } else if (item.Type() == NGInlineItem::kOpenTag) { 128 } else if (item.Type() == NGInlineItem::kOpenTag) {
122 HandleOpenTag(item, item_result); 129 HandleOpenTag(item, item_result);
123 state = LineBreakState::kNotBreakable; 130 state = LineBreakState::kNotBreakable;
124 } else if (item.Type() == NGInlineItem::kFloating) { 131 } else if (item.Type() == NGInlineItem::kFloating) {
125 HandleFloat(item, item_results, algorithm); 132 HandleFloat(item, item_results, algorithm);
126 } else { 133 } else {
127 MoveToNextOf(item); 134 MoveToNextOf(item);
128 } 135 }
129 } 136 }
130 if (state == LineBreakState::kIsBreakable && position_ > available_width_) 137 if (state == LineBreakState::kIsBreakable && position_ > available_width_)
131 return HandleOverflow(item_results); 138 return HandleOverflow(line_info);
139 line_info->SetIsLastLine(true);
132 } 140 }
133 141
134 NGLineBreaker::LineBreakState NGLineBreaker::HandleText( 142 NGLineBreaker::LineBreakState NGLineBreaker::HandleText(
135 const NGInlineItem& item, 143 const NGInlineItem& item,
136 NGInlineItemResult* item_result) { 144 NGInlineItemResult* item_result) {
137 DCHECK_EQ(item.Type(), NGInlineItem::kText); 145 DCHECK_EQ(item.Type(), NGInlineItem::kText);
138 146
139 // If the start offset is at the item boundary, try to add the entire item. 147 // If the start offset is at the item boundary, try to add the entire item.
140 if (offset_ == item.StartOffset()) { 148 if (offset_ == item.StartOffset()) {
141 item_result->inline_size = item.InlineSize(); 149 item_result->inline_size = item.InlineSize();
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
326 position_ += item_result->inline_size; 334 position_ += item_result->inline_size;
327 } 335 }
328 DCHECK(item.GetLayoutObject() && item.GetLayoutObject()->Parent()); 336 DCHECK(item.GetLayoutObject() && item.GetLayoutObject()->Parent());
329 UpdateBreakIterator(item.GetLayoutObject()->Parent()->StyleRef()); 337 UpdateBreakIterator(item.GetLayoutObject()->Parent()->StyleRef());
330 MoveToNextOf(item); 338 MoveToNextOf(item);
331 } 339 }
332 340
333 // Handles when the last item overflows. 341 // Handles when the last item overflows.
334 // At this point, item_results does not fit into the current line, and there 342 // At this point, item_results does not fit into the current line, and there
335 // are no break opportunities in item_results.back(). 343 // are no break opportunities in item_results.back().
336 void NGLineBreaker::HandleOverflow(NGInlineItemResults* item_results) { 344 void NGLineBreaker::HandleOverflow(NGLineInfo* line_info) {
345 NGInlineItemResults* item_results = &line_info->Results();
337 const Vector<NGInlineItem>& items = node_.Items(); 346 const Vector<NGInlineItem>& items = node_.Items();
338 LayoutUnit rewind_width = available_width_ - position_; 347 LayoutUnit rewind_width = available_width_ - position_;
339 DCHECK_LT(rewind_width, 0); 348 DCHECK_LT(rewind_width, 0);
340 349
341 // Search for a break opportunity that can fit. 350 // Search for a break opportunity that can fit.
342 // Also keep track of the first break opportunity in case of overflow. 351 // Also keep track of the first break opportunity in case of overflow.
343 unsigned break_before = 0; 352 unsigned break_before = 0;
344 unsigned break_before_if_before_allow = 0; 353 unsigned break_before_if_before_allow = 0;
345 LayoutUnit rewind_width_if_before_allow; 354 LayoutUnit rewind_width_if_before_allow;
346 bool last_item_prohibits_break_before = true; 355 bool last_item_prohibits_break_before = true;
347 for (unsigned i = item_results->size(); i;) { 356 for (unsigned i = item_results->size(); i;) {
348 NGInlineItemResult* item_result = &(*item_results)[--i]; 357 NGInlineItemResult* item_result = &(*item_results)[--i];
349 const NGInlineItem& item = items[item_result->item_index]; 358 const NGInlineItem& item = items[item_result->item_index];
350 rewind_width += item_result->inline_size; 359 rewind_width += item_result->inline_size;
351 if (item.Type() == NGInlineItem::kText || 360 if (item.Type() == NGInlineItem::kText ||
352 item.Type() == NGInlineItem::kAtomicInline) { 361 item.Type() == NGInlineItem::kAtomicInline) {
353 // Try to break inside of this item. 362 // Try to break inside of this item.
354 if (item.Type() == NGInlineItem::kText && rewind_width >= 0 && 363 if (item.Type() == NGInlineItem::kText && rewind_width >= 0 &&
355 !item_result->no_break_opportunities_inside) { 364 !item_result->no_break_opportunities_inside) {
356 // When the text fits but its right margin does not, the break point 365 // When the text fits but its right margin does not, the break point
357 // must not be at the end. 366 // must not be at the end.
358 LayoutUnit item_available_width = 367 LayoutUnit item_available_width =
359 std::min(rewind_width, item_result->inline_size - 1); 368 std::min(rewind_width, item_result->inline_size - 1);
360 BreakText(item_result, item, item_available_width); 369 BreakText(item_result, item, item_available_width);
361 if (item_result->inline_size <= item_available_width) { 370 if (item_result->inline_size <= item_available_width) {
362 DCHECK_LT(item_result->end_offset, item.EndOffset()); 371 DCHECK_LT(item_result->end_offset, item.EndOffset());
363 DCHECK(!item_result->prohibit_break_after); 372 DCHECK(!item_result->prohibit_break_after);
364 return Rewind(item_results, i + 1); 373 return Rewind(line_info, i + 1);
365 } 374 }
366 if (!item_result->prohibit_break_after && 375 if (!item_result->prohibit_break_after &&
367 !last_item_prohibits_break_before) { 376 !last_item_prohibits_break_before) {
368 break_before = i + 1; 377 break_before = i + 1;
369 } 378 }
370 } 379 }
371 380
372 // Try to break after this item. 381 // Try to break after this item.
373 if (break_before_if_before_allow && !item_result->prohibit_break_after) { 382 if (break_before_if_before_allow && !item_result->prohibit_break_after) {
374 if (rewind_width_if_before_allow >= 0) 383 if (rewind_width_if_before_allow >= 0)
375 return Rewind(item_results, break_before_if_before_allow); 384 return Rewind(line_info, break_before_if_before_allow);
376 break_before = break_before_if_before_allow; 385 break_before = break_before_if_before_allow;
377 } 386 }
378 387
379 // Otherwise, before this item is a possible break point. 388 // Otherwise, before this item is a possible break point.
380 break_before_if_before_allow = i; 389 break_before_if_before_allow = i;
381 rewind_width_if_before_allow = rewind_width; 390 rewind_width_if_before_allow = rewind_width;
382 last_item_prohibits_break_before = false; 391 last_item_prohibits_break_before = false;
383 } else if (item.Type() == NGInlineItem::kCloseTag) { 392 } else if (item.Type() == NGInlineItem::kCloseTag) {
384 last_item_prohibits_break_before = true; 393 last_item_prohibits_break_before = true;
385 } else { 394 } else {
386 if (i + 1 == break_before_if_before_allow) { 395 if (i + 1 == break_before_if_before_allow) {
387 break_before_if_before_allow = i; 396 break_before_if_before_allow = i;
388 rewind_width_if_before_allow = rewind_width; 397 rewind_width_if_before_allow = rewind_width;
389 } 398 }
390 last_item_prohibits_break_before = false; 399 last_item_prohibits_break_before = false;
391 } 400 }
392 } 401 }
393 402
394 // The rewind point did not found, let this line overflow. 403 // The rewind point did not found, let this line overflow.
395 // If there was a break opporunity, the overflow should stop there. 404 // If there was a break opporunity, the overflow should stop there.
396 if (break_before) 405 if (break_before)
397 Rewind(item_results, break_before); 406 return Rewind(line_info, break_before);
407
408 line_info->SetIsLastLine(item_index_ >= items.size());
398 } 409 }
399 410
400 void NGLineBreaker::Rewind(NGInlineItemResults* item_results, 411 void NGLineBreaker::Rewind(NGLineInfo* line_info, unsigned new_end) {
401 unsigned new_end) { 412 NGInlineItemResults* item_results = &line_info->Results();
402 // TODO(kojii): Should we keep results for the next line? We don't need to 413 // TODO(kojii): Should we keep results for the next line? We don't need to
403 // re-layout atomic inlines. 414 // re-layout atomic inlines.
404 // TODO(kojii): Removing processed floats is likely a problematic. Keep 415 // TODO(kojii): Removing processed floats is likely a problematic. Keep
405 // floats in this line, or keep it for the next line. 416 // floats in this line, or keep it for the next line.
406 item_results->Shrink(new_end); 417 item_results->Shrink(new_end);
407 418
408 MoveToNextOf(item_results->back()); 419 MoveToNextOf(item_results->back());
420 DCHECK_LT(item_index_, node_.Items().size());
421 line_info->SetIsLastLine(false);
409 } 422 }
410 423
411 void NGLineBreaker::UpdateBreakIterator(const ComputedStyle& style) { 424 void NGLineBreaker::UpdateBreakIterator(const ComputedStyle& style) {
412 auto_wrap_ = style.AutoWrap(); 425 auto_wrap_ = style.AutoWrap();
413 426
414 if (auto_wrap_) { 427 if (auto_wrap_) {
415 break_iterator_.SetLocale(style.LocaleForLineBreakIterator()); 428 break_iterator_.SetLocale(style.LocaleForLineBreakIterator());
416 429
417 if (style.WordBreak() == EWordBreak::kBreakAll || 430 if (style.WordBreak() == EWordBreak::kBreakAll ||
418 style.WordBreak() == EWordBreak::kBreakWord) { 431 style.WordBreak() == EWordBreak::kBreakWord) {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
460 } 473 }
461 474
462 RefPtr<NGInlineBreakToken> NGLineBreaker::CreateBreakToken() const { 475 RefPtr<NGInlineBreakToken> NGLineBreaker::CreateBreakToken() const {
463 const Vector<NGInlineItem>& items = node_.Items(); 476 const Vector<NGInlineItem>& items = node_.Items();
464 if (item_index_ >= items.size()) 477 if (item_index_ >= items.size())
465 return nullptr; 478 return nullptr;
466 return NGInlineBreakToken::Create(node_, item_index_, offset_); 479 return NGInlineBreakToken::Create(node_, item_index_, offset_);
467 } 480 }
468 481
469 } // namespace blink 482 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698