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

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

Issue 2951213005: [LayoutNG] Support objects that are opaque to whitespace collapsing (Closed)
Patch Set: Renamed to AppendOpaque Created 3 years, 5 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_inline_items_builder.h" 5 #include "core/layout/ng/inline/ng_inline_items_builder.h"
6 6
7 #include "core/layout/LayoutObject.h" 7 #include "core/layout/LayoutObject.h"
8 #include "core/layout/ng/inline/ng_inline_node.h" 8 #include "core/layout/ng/inline/ng_inline_node.h"
9 #include "core/style/ComputedStyle.h" 9 #include "core/style/ComputedStyle.h"
10 10
11 namespace blink { 11 namespace blink {
12 12
13 NGInlineItemsBuilder::~NGInlineItemsBuilder() { 13 NGInlineItemsBuilder::~NGInlineItemsBuilder() {
14 DCHECK_EQ(0u, exits_.size()); 14 DCHECK_EQ(0u, exits_.size());
15 DCHECK_EQ(text_.length(), items_->IsEmpty() ? 0 : items_->back().EndOffset()); 15 DCHECK_EQ(text_.length(), items_->IsEmpty() ? 0 : items_->back().EndOffset());
16 } 16 }
17 17
18 String NGInlineItemsBuilder::ToString() { 18 String NGInlineItemsBuilder::ToString() {
19 // Segment Break Transformation Rules[1] defines to keep trailing new lines, 19 // Segment Break Transformation Rules[1] defines to keep trailing new lines,
20 // but it will be removed in Phase II[2]. We prefer not to add trailing new 20 // but it will be removed in Phase II[2]. We prefer not to add trailing new
21 // lines and collapsible spaces in Phase I. 21 // lines and collapsible spaces in Phase I.
22 // [1] https://drafts.csswg.org/css-text-3/#line-break-transform 22 // [1] https://drafts.csswg.org/css-text-3/#line-break-transform
23 // [2] https://drafts.csswg.org/css-text-3/#white-space-phase-2 23 // [2] https://drafts.csswg.org/css-text-3/#white-space-phase-2
24 unsigned next_start_offset = text_.length(); 24 RemoveTrailingCollapsibleSpaceIfExists();
25 RemoveTrailingCollapsibleSpaceIfExists(&next_start_offset);
26 25
27 return text_.ToString(); 26 return text_.ToString();
28 } 27 }
29 28
30 // Determine "Ambiguous" East Asian Width is Wide or Narrow. 29 // Determine "Ambiguous" East Asian Width is Wide or Narrow.
31 // Unicode East Asian Width 30 // Unicode East Asian Width
32 // http://unicode.org/reports/tr11/ 31 // http://unicode.org/reports/tr11/
33 static bool IsAmbiguosEastAsianWidthWide(const ComputedStyle* style) { 32 static bool IsAmbiguosEastAsianWidthWide(const ComputedStyle* style) {
34 UScriptCode script = style->GetFontDescription().GetScript(); 33 UScriptCode script = style->GetFontDescription().GetScript();
35 return script == USCRIPT_KATAKANA_OR_HIRAGANA || 34 return script == USCRIPT_KATAKANA_OR_HIRAGANA ||
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
167 if (c == kSpaceCharacter || c == kTabulationCharacter) { 166 if (c == kSpaceCharacter || c == kTabulationCharacter) {
168 if (last_collapsible_space_ == CollapsibleSpace::kNone) { 167 if (last_collapsible_space_ == CollapsibleSpace::kNone) {
169 text_.Append(kSpaceCharacter); 168 text_.Append(kSpaceCharacter);
170 last_collapsible_space_ = CollapsibleSpace::kSpace; 169 last_collapsible_space_ = CollapsibleSpace::kSpace;
171 } 170 }
172 i++; 171 i++;
173 continue; 172 continue;
174 } 173 }
175 174
176 if (last_collapsible_space_ == CollapsibleSpace::kNewline) { 175 if (last_collapsible_space_ == CollapsibleSpace::kNewline) {
177 RemoveTrailingCollapsibleNewlineIfNeeded(&start_offset, string, i, style); 176 RemoveTrailingCollapsibleNewlineIfNeeded(string, i, style);
177 start_offset = std::min(start_offset, text_.length());
178 } 178 }
179 179
180 size_t end_of_non_space = string.Find(IsCollapsibleSpace, i + 1); 180 size_t end_of_non_space = string.Find(IsCollapsibleSpace, i + 1);
181 if (end_of_non_space == kNotFound) 181 if (end_of_non_space == kNotFound)
182 end_of_non_space = string.length(); 182 end_of_non_space = string.length();
183 text_.Append(string, i, end_of_non_space - i); 183 text_.Append(string, i, end_of_non_space - i);
184 i = end_of_non_space; 184 i = end_of_non_space;
185 last_collapsible_space_ = CollapsibleSpace::kNone; 185 last_collapsible_space_ = CollapsibleSpace::kNone;
186 } 186 }
187 187
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
233 if (end == kNotFound) 233 if (end == kNotFound)
234 end = string.length(); 234 end = string.length();
235 AppendWithWhiteSpaceCollapsing(string, start, end, style, layout_object); 235 AppendWithWhiteSpaceCollapsing(string, start, end, style, layout_object);
236 start = end; 236 start = end;
237 } 237 }
238 } 238 }
239 239
240 void NGInlineItemsBuilder::AppendForcedBreak(const ComputedStyle* style, 240 void NGInlineItemsBuilder::AppendForcedBreak(const ComputedStyle* style,
241 LayoutObject* layout_object) { 241 LayoutObject* layout_object) {
242 // Remove collapsible spaces immediately before a preserved newline. 242 // Remove collapsible spaces immediately before a preserved newline.
243 unsigned start_offset = text_.length(); 243 RemoveTrailingCollapsibleSpaceIfExists();
244 RemoveTrailingCollapsibleSpaceIfExists(&start_offset);
245 244
246 Append(NGInlineItem::kControl, kNewlineCharacter, style, layout_object); 245 Append(NGInlineItem::kControl, kNewlineCharacter, style, layout_object);
247 246
248 // Remove collapsible spaces immediately after a preserved newline. 247 // Remove collapsible spaces immediately after a preserved newline.
249 last_collapsible_space_ = CollapsibleSpace::kSpace; 248 last_collapsible_space_ = CollapsibleSpace::kSpace;
250 } 249 }
251 250
252 void NGInlineItemsBuilder::Append(NGInlineItem::NGInlineItemType type, 251 void NGInlineItemsBuilder::Append(NGInlineItem::NGInlineItemType type,
253 UChar character, 252 UChar character,
254 const ComputedStyle* style, 253 const ComputedStyle* style,
255 LayoutObject* layout_object) { 254 LayoutObject* layout_object) {
256 DCHECK_NE(character, kSpaceCharacter); 255 DCHECK_NE(character, kSpaceCharacter);
257 DCHECK_NE(character, kZeroWidthSpaceCharacter); 256 DCHECK_NE(character, kZeroWidthSpaceCharacter);
258 257
259 text_.Append(character); 258 text_.Append(character);
260 unsigned end_offset = text_.length(); 259 unsigned end_offset = text_.length();
261 AppendItem(items_, type, end_offset - 1, end_offset, style, layout_object); 260 AppendItem(items_, type, end_offset - 1, end_offset, style, layout_object);
262 last_collapsible_space_ = CollapsibleSpace::kNone; 261 last_collapsible_space_ = CollapsibleSpace::kNone;
263 } 262 }
264 263
265 void NGInlineItemsBuilder::Append(NGInlineItem::NGInlineItemType type, 264 void NGInlineItemsBuilder::AppendOpaque(NGInlineItem::NGInlineItemType type,
266 const ComputedStyle* style, 265 UChar character) {
267 LayoutObject* layout_object) { 266 text_.Append(character);
267 unsigned end_offset = text_.length();
268 AppendItem(items_, type, end_offset - 1, end_offset, nullptr, nullptr);
269 }
270
271 void NGInlineItemsBuilder::AppendOpaque(NGInlineItem::NGInlineItemType type,
272 const ComputedStyle* style,
273 LayoutObject* layout_object) {
268 unsigned end_offset = text_.length(); 274 unsigned end_offset = text_.length();
269 AppendItem(items_, type, end_offset, end_offset, style, layout_object); 275 AppendItem(items_, type, end_offset, end_offset, style, layout_object);
270 } 276 }
271 277
278 // Removes the collapsible newline at the end of |text_| if exists and the
279 // removal conditions met.
272 void NGInlineItemsBuilder::RemoveTrailingCollapsibleNewlineIfNeeded( 280 void NGInlineItemsBuilder::RemoveTrailingCollapsibleNewlineIfNeeded(
273 unsigned* next_start_offset,
274 const String& after, 281 const String& after,
275 unsigned after_index, 282 unsigned after_index,
276 const ComputedStyle* after_style) { 283 const ComputedStyle* after_style) {
277 DCHECK_EQ(last_collapsible_space_, CollapsibleSpace::kNewline); 284 DCHECK_EQ(last_collapsible_space_, CollapsibleSpace::kNewline);
278 285
279 if (text_.IsEmpty() || text_[text_.length() - 1] != kSpaceCharacter) 286 if (text_.IsEmpty() || text_[text_.length() - 1] != kSpaceCharacter)
280 return; 287 return;
281 288
282 const ComputedStyle* before_style = after_style; 289 const ComputedStyle* before_style = after_style;
283 if (!items_->IsEmpty()) { 290 if (!items_->IsEmpty()) {
284 NGInlineItem& item = items_->back(); 291 NGInlineItem& item = items_->back();
285 if (text_.length() < item.EndOffset() + 2) 292 if (text_.length() < item.EndOffset() + 2)
286 before_style = item.Style(); 293 before_style = item.Style();
287 } 294 }
288 295
289 if (ShouldRemoveNewline(text_, before_style, after, after_index, after_style)) 296 if (ShouldRemoveNewline(text_, before_style, after, after_index, after_style))
290 RemoveTrailingCollapsibleSpace(next_start_offset); 297 RemoveTrailingCollapsibleSpace(text_.length() - 1);
291 } 298 }
292 299
293 void NGInlineItemsBuilder::RemoveTrailingCollapsibleSpaceIfExists( 300 // Removes the collapsible space at the end of |text_| if exists.
294 unsigned* next_start_offset) { 301 void NGInlineItemsBuilder::RemoveTrailingCollapsibleSpaceIfExists() {
295 if (last_collapsible_space_ != CollapsibleSpace::kNone && !text_.IsEmpty() && 302 if (last_collapsible_space_ == CollapsibleSpace::kNone || text_.IsEmpty())
296 text_[text_.length() - 1] == kSpaceCharacter) 303 return;
297 RemoveTrailingCollapsibleSpace(next_start_offset); 304
305 // Look for the last space character since characters that are opaque to
306 // whitespace collapsing may be appended.
307 for (unsigned i = text_.length(); i;) {
308 UChar ch = text_[--i];
309 if (ch == kSpaceCharacter) {
310 RemoveTrailingCollapsibleSpace(i);
311 return;
312 }
313
314 // AppendForcedBreak sets CollapsibleSpace::kSpace to ignore leading
315 // spaces. In this case, the trailing collapsible space does not exist.
316 if (ch == kNewlineCharacter)
317 return;
318 }
319 NOTREACHED();
298 } 320 }
299 321
300 void NGInlineItemsBuilder::RemoveTrailingCollapsibleSpace( 322 // Removes the collapsible space at the specified index.
301 unsigned* next_start_offset) { 323 void NGInlineItemsBuilder::RemoveTrailingCollapsibleSpace(unsigned index) {
302 DCHECK_NE(last_collapsible_space_, CollapsibleSpace::kNone); 324 DCHECK_NE(last_collapsible_space_, CollapsibleSpace::kNone);
303 DCHECK(!text_.IsEmpty()); 325 DCHECK(!text_.IsEmpty());
304 DCHECK_EQ(text_[text_.length() - 1], kSpaceCharacter); 326 DCHECK_EQ(text_[index], kSpaceCharacter);
305 327
306 unsigned new_size = text_.length() - 1; 328 text_.erase(index);
307 text_.Resize(new_size);
308 last_collapsible_space_ = CollapsibleSpace::kNone; 329 last_collapsible_space_ = CollapsibleSpace::kNone;
309 330
310 if (*next_start_offset <= new_size) 331 // Adjust items if the removed space is already included.
311 return;
312 *next_start_offset = new_size;
313
314 // Adjust the last item if the removed space is already appended.
315 for (unsigned i = items_->size(); i > 0;) { 332 for (unsigned i = items_->size(); i > 0;) {
316 NGInlineItem& item = (*items_)[--i]; 333 NGInlineItem& item = (*items_)[--i];
317 DCHECK_EQ(item.EndOffset(), new_size + 1); 334 if (index >= item.EndOffset())
318 if (item.Type() == NGInlineItem::kText) { 335 return;
319 DCHECK_GE(item.Length(), 1u); 336 if (item.StartOffset() <= index) {
320 if (item.Length() > 1) 337 if (item.Length() == 1) {
321 item.SetEndOffset(new_size); 338 DCHECK_EQ(item.StartOffset(), index);
322 else 339 DCHECK_EQ(item.Type(), NGInlineItem::kText);
323 items_->erase(i); 340 items_->erase(i);
324 break; 341 } else {
342 item.SetEndOffset(item.EndOffset() - 1);
343 }
344 return;
325 } 345 }
326 if (!item.Length()) { 346
327 // Trailing spaces can be removed across non-character items. 347 // Trailing spaces can be removed across non-character items.
328 item.SetOffset(new_size, new_size); 348 // Adjust their offsets if after the removed index.
329 continue; 349 item.SetOffset(item.StartOffset() - 1, item.EndOffset() - 1);
330 }
331 NOTREACHED();
332 break;
333 } 350 }
334 } 351 }
335 352
336 void NGInlineItemsBuilder::AppendBidiControl(const ComputedStyle* style, 353 void NGInlineItemsBuilder::AppendBidiControl(const ComputedStyle* style,
337 UChar ltr, 354 UChar ltr,
338 UChar rtl) { 355 UChar rtl) {
339 Append(NGInlineItem::kBidiControl, 356 AppendOpaque(NGInlineItem::kBidiControl,
340 style->Direction() == TextDirection::kRtl ? rtl : ltr); 357 IsLtr(style->Direction()) ? ltr : rtl);
341 } 358 }
342 359
343 void NGInlineItemsBuilder::EnterBlock(const ComputedStyle* style) { 360 void NGInlineItemsBuilder::EnterBlock(const ComputedStyle* style) {
344 // Handle bidi-override on the block itself. 361 // Handle bidi-override on the block itself.
345 switch (style->GetUnicodeBidi()) { 362 switch (style->GetUnicodeBidi()) {
346 case UnicodeBidi::kNormal: 363 case UnicodeBidi::kNormal:
347 case UnicodeBidi::kEmbed: 364 case UnicodeBidi::kEmbed:
348 case UnicodeBidi::kIsolate: 365 case UnicodeBidi::kIsolate:
349 // Isolate and embed values are enforced by default and redundant on the 366 // Isolate and embed values are enforced by default and redundant on the
350 // block elements. 367 // block elements.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
382 AppendBidiControl(style, kLeftToRightOverrideCharacter, 399 AppendBidiControl(style, kLeftToRightOverrideCharacter,
383 kRightToLeftOverrideCharacter); 400 kRightToLeftOverrideCharacter);
384 Enter(node, kPopDirectionalFormattingCharacter); 401 Enter(node, kPopDirectionalFormattingCharacter);
385 break; 402 break;
386 case UnicodeBidi::kIsolate: 403 case UnicodeBidi::kIsolate:
387 AppendBidiControl(style, kLeftToRightIsolateCharacter, 404 AppendBidiControl(style, kLeftToRightIsolateCharacter,
388 kRightToLeftIsolateCharacter); 405 kRightToLeftIsolateCharacter);
389 Enter(node, kPopDirectionalIsolateCharacter); 406 Enter(node, kPopDirectionalIsolateCharacter);
390 break; 407 break;
391 case UnicodeBidi::kPlaintext: 408 case UnicodeBidi::kPlaintext:
392 Append(NGInlineItem::kBidiControl, kFirstStrongIsolateCharacter); 409 AppendOpaque(NGInlineItem::kBidiControl, kFirstStrongIsolateCharacter);
393 Enter(node, kPopDirectionalIsolateCharacter); 410 Enter(node, kPopDirectionalIsolateCharacter);
394 break; 411 break;
395 case UnicodeBidi::kIsolateOverride: 412 case UnicodeBidi::kIsolateOverride:
396 Append(NGInlineItem::kBidiControl, kFirstStrongIsolateCharacter); 413 AppendOpaque(NGInlineItem::kBidiControl, kFirstStrongIsolateCharacter);
397 AppendBidiControl(style, kLeftToRightOverrideCharacter, 414 AppendBidiControl(style, kLeftToRightOverrideCharacter,
398 kRightToLeftOverrideCharacter); 415 kRightToLeftOverrideCharacter);
399 Enter(node, kPopDirectionalIsolateCharacter); 416 Enter(node, kPopDirectionalIsolateCharacter);
400 Enter(node, kPopDirectionalFormattingCharacter); 417 Enter(node, kPopDirectionalFormattingCharacter);
401 break; 418 break;
402 } 419 }
403 420
404 Append(NGInlineItem::kOpenTag, style, node); 421 AppendOpaque(NGInlineItem::kOpenTag, style, node);
405 } 422 }
406 423
407 void NGInlineItemsBuilder::Enter(LayoutObject* node, UChar character_to_exit) { 424 void NGInlineItemsBuilder::Enter(LayoutObject* node, UChar character_to_exit) {
408 exits_.push_back(OnExitNode{node, character_to_exit}); 425 exits_.push_back(OnExitNode{node, character_to_exit});
409 has_bidi_controls_ = true; 426 has_bidi_controls_ = true;
410 } 427 }
411 428
412 void NGInlineItemsBuilder::ExitBlock() { 429 void NGInlineItemsBuilder::ExitBlock() {
413 Exit(nullptr); 430 Exit(nullptr);
414 } 431 }
415 432
416 void NGInlineItemsBuilder::ExitInline(LayoutObject* node) { 433 void NGInlineItemsBuilder::ExitInline(LayoutObject* node) {
417 DCHECK(node); 434 DCHECK(node);
418 435
419 Append(NGInlineItem::kCloseTag, node->Style(), node); 436 AppendOpaque(NGInlineItem::kCloseTag, node->Style(), node);
420 437
421 Exit(node); 438 Exit(node);
422 } 439 }
423 440
424 void NGInlineItemsBuilder::Exit(LayoutObject* node) { 441 void NGInlineItemsBuilder::Exit(LayoutObject* node) {
425 while (!exits_.IsEmpty() && exits_.back().node == node) { 442 while (!exits_.IsEmpty() && exits_.back().node == node) {
426 Append(NGInlineItem::kBidiControl, exits_.back().character); 443 AppendOpaque(NGInlineItem::kBidiControl, exits_.back().character);
427 exits_.pop_back(); 444 exits_.pop_back();
428 } 445 }
429 } 446 }
430 447
431 } // namespace blink 448 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698