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

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

Issue 2943573002: Make NGInlineItemsBuilder construct whitespace-collapsed offset mapping (Closed)
Patch Set: Mon Jun 19 14:03:52 PDT 2017 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_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 unsigned next_start_offset = text_.length();
25 RemoveTrailingCollapsibleSpaceIfExists(&next_start_offset); 25 RemoveTrailingCollapsibleSpaceIfExists(
26 &next_start_offset,
27 input_strings_lengths_.size() ? input_strings_lengths_.back() : 0);
26 28
27 return text_.ToString(); 29 return text_.ToString();
28 } 30 }
29 31
30 // Determine "Ambiguous" East Asian Width is Wide or Narrow. 32 // Determine "Ambiguous" East Asian Width is Wide or Narrow.
31 // Unicode East Asian Width 33 // Unicode East Asian Width
32 // http://unicode.org/reports/tr11/ 34 // http://unicode.org/reports/tr11/
33 static bool IsAmbiguosEastAsianWidthWide(const ComputedStyle* style) { 35 static bool IsAmbiguosEastAsianWidthWide(const ComputedStyle* style) {
34 UScriptCode script = style->GetFontDescription().GetScript(); 36 UScriptCode script = style->GetFontDescription().GetScript();
35 return script == USCRIPT_KATAKANA_OR_HIRAGANA || 37 return script == USCRIPT_KATAKANA_OR_HIRAGANA ||
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
117 return c == kSpaceCharacter || c == kTabulationCharacter || 119 return c == kSpaceCharacter || c == kTabulationCharacter ||
118 c == kNewlineCharacter; 120 c == kNewlineCharacter;
119 } 121 }
120 122
121 // Characters needing a separate control item than other text items. 123 // Characters needing a separate control item than other text items.
122 // It makes the line breaker easier to handle. 124 // It makes the line breaker easier to handle.
123 static inline bool IsControlItemCharacter(UChar c) { 125 static inline bool IsControlItemCharacter(UChar c) {
124 return c == kTabulationCharacter || c == kNewlineCharacter; 126 return c == kTabulationCharacter || c == kNewlineCharacter;
125 } 127 }
126 128
129 // Returns the largest integer in [0, |max|) that is absent in |integers|, or
130 // kNotFound if such an integer does not exist.
131 static size_t GetLargestAbsentInteger(const Vector<unsigned>& integers,
132 unsigned max) {
133 DCHECK(integers.IsEmpty() || integers.back() < max);
134 if (!max || integers.size() == max)
135 return kNotFound;
136 if (integers.IsEmpty() || integers.back() + 1 < max)
137 return max - 1;
138 for (unsigned i = integers.size() - 1; i;) {
139 DCHECK_LT(integers[i - 1], integers[i]);
140 if (integers[i - 1] + 1 < integers[i] - 1)
141 return integers[i] - 1;
142 --i;
143 }
144 DCHECK_GT(integers[0], 0u);
145 return integers[0] - 1;
146 }
147
127 void NGInlineItemsBuilder::Append(const String& string, 148 void NGInlineItemsBuilder::Append(const String& string,
128 const ComputedStyle* style, 149 const ComputedStyle* style,
129 LayoutObject* layout_object) { 150 LayoutObject* layout_object) {
151 if (collapsed_indexes_) {
152 input_strings_lengths_.push_back(string.length());
153 collapsed_indexes_->emplace_back();
154 }
155
130 if (string.IsEmpty()) 156 if (string.IsEmpty())
131 return; 157 return;
132 text_.ReserveCapacity(string.length()); 158 text_.ReserveCapacity(string.length());
133 159
134 EWhiteSpace whitespace = style->WhiteSpace(); 160 EWhiteSpace whitespace = style->WhiteSpace();
135 if (!ComputedStyle::CollapseWhiteSpace(whitespace)) 161 if (!ComputedStyle::CollapseWhiteSpace(whitespace))
136 return AppendWithoutWhiteSpaceCollapsing(string, style, layout_object); 162 return AppendWithoutWhiteSpaceCollapsing(string, style, layout_object);
137 if (ComputedStyle::PreserveNewline(whitespace) && !is_svgtext_) 163 if (ComputedStyle::PreserveNewline(whitespace) && !is_svgtext_)
138 return AppendWithPreservingNewlines(string, style, layout_object); 164 return AppendWithPreservingNewlines(string, style, layout_object);
139 165
140 AppendWithWhiteSpaceCollapsing(string, 0, string.length(), style, 166 AppendWithWhiteSpaceCollapsing(string, 0, string.length(), style,
141 layout_object); 167 layout_object);
142 } 168 }
143 169
144 void NGInlineItemsBuilder::AppendWithWhiteSpaceCollapsing( 170 void NGInlineItemsBuilder::AppendWithWhiteSpaceCollapsing(
145 const String& string, 171 const String& string,
146 unsigned start, 172 unsigned start,
147 unsigned end, 173 unsigned end,
148 const ComputedStyle* style, 174 const ComputedStyle* style,
149 LayoutObject* layout_object) { 175 LayoutObject* layout_object) {
150 unsigned start_offset = text_.length(); 176 unsigned start_offset = text_.length();
151 for (unsigned i = start; i < end;) { 177 for (unsigned i = start; i < end;) {
152 UChar c = string[i]; 178 UChar c = string[i];
153 if (c == kNewlineCharacter) { 179 if (c == kNewlineCharacter) {
154 // LayoutBR does not set preserve_newline, but should be preserved. 180 // LayoutBR does not set preserve_newline, but should be preserved.
155 if (!i && end == 1 && layout_object && layout_object->IsBR()) { 181 if (!i && end == 1 && layout_object && layout_object->IsBR()) {
156 AppendForcedBreak(style, layout_object); 182 AppendForcedBreak(style, layout_object, i);
157 return; 183 return;
158 } 184 }
159 185
160 if (last_collapsible_space_ == CollapsibleSpace::kNone) 186 if (last_collapsible_space_ == CollapsibleSpace::kNone)
161 text_.Append(kSpaceCharacter); 187 text_.Append(kSpaceCharacter);
188 else if (collapsed_indexes_)
189 collapsed_indexes_->back().push_back(i);
162 last_collapsible_space_ = CollapsibleSpace::kNewline; 190 last_collapsible_space_ = CollapsibleSpace::kNewline;
163 i++; 191 i++;
164 continue; 192 continue;
165 } 193 }
166 194
167 if (c == kSpaceCharacter || c == kTabulationCharacter) { 195 if (c == kSpaceCharacter || c == kTabulationCharacter) {
168 if (last_collapsible_space_ == CollapsibleSpace::kNone) { 196 if (last_collapsible_space_ == CollapsibleSpace::kNone) {
169 text_.Append(kSpaceCharacter); 197 text_.Append(kSpaceCharacter);
170 last_collapsible_space_ = CollapsibleSpace::kSpace; 198 last_collapsible_space_ = CollapsibleSpace::kSpace;
199 } else if (collapsed_indexes_) {
200 collapsed_indexes_->back().push_back(i);
171 } 201 }
172 i++; 202 i++;
173 continue; 203 continue;
174 } 204 }
175 205
176 if (last_collapsible_space_ == CollapsibleSpace::kNewline) { 206 if (last_collapsible_space_ == CollapsibleSpace::kNewline) {
177 RemoveTrailingCollapsibleNewlineIfNeeded(&start_offset, string, i, style); 207 RemoveTrailingCollapsibleNewlineIfNeeded(&start_offset, string, i, style);
178 } 208 }
179 209
180 size_t end_of_non_space = string.Find(IsCollapsibleSpace, i + 1); 210 size_t end_of_non_space = string.Find(IsCollapsibleSpace, i + 1);
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 247
218 last_collapsible_space_ = CollapsibleSpace::kNone; 248 last_collapsible_space_ = CollapsibleSpace::kNone;
219 } 249 }
220 250
221 void NGInlineItemsBuilder::AppendWithPreservingNewlines( 251 void NGInlineItemsBuilder::AppendWithPreservingNewlines(
222 const String& string, 252 const String& string,
223 const ComputedStyle* style, 253 const ComputedStyle* style,
224 LayoutObject* layout_object) { 254 LayoutObject* layout_object) {
225 for (unsigned start = 0; start < string.length();) { 255 for (unsigned start = 0; start < string.length();) {
226 if (string[start] == kNewlineCharacter) { 256 if (string[start] == kNewlineCharacter) {
227 AppendForcedBreak(style, layout_object); 257 AppendForcedBreak(style, layout_object, start);
228 start++; 258 start++;
229 continue; 259 continue;
230 } 260 }
231 261
232 size_t end = string.find(kNewlineCharacter, start + 1); 262 size_t end = string.find(kNewlineCharacter, start + 1);
233 if (end == kNotFound) 263 if (end == kNotFound)
234 end = string.length(); 264 end = string.length();
235 AppendWithWhiteSpaceCollapsing(string, start, end, style, layout_object); 265 AppendWithWhiteSpaceCollapsing(string, start, end, style, layout_object);
236 start = end; 266 start = end;
237 } 267 }
238 } 268 }
239 269
240 void NGInlineItemsBuilder::AppendForcedBreak(const ComputedStyle* style, 270 void NGInlineItemsBuilder::AppendForcedBreak(const ComputedStyle* style,
241 LayoutObject* layout_object) { 271 LayoutObject* layout_object,
272 unsigned index) {
242 // Remove collapsible spaces immediately before a preserved newline. 273 // Remove collapsible spaces immediately before a preserved newline.
243 unsigned start_offset = text_.length(); 274 unsigned start_offset = text_.length();
244 RemoveTrailingCollapsibleSpaceIfExists(&start_offset); 275 RemoveTrailingCollapsibleSpaceIfExists(&start_offset, index);
245 276
246 Append(NGInlineItem::kControl, kNewlineCharacter, style, layout_object); 277 Append(NGInlineItem::kControl, kNewlineCharacter, style, layout_object);
247 278
248 // Remove collapsible spaces immediately after a preserved newline. 279 // Remove collapsible spaces immediately after a preserved newline.
249 last_collapsible_space_ = CollapsibleSpace::kSpace; 280 last_collapsible_space_ = CollapsibleSpace::kSpace;
250 } 281 }
251 282
252 void NGInlineItemsBuilder::Append(NGInlineItem::NGInlineItemType type, 283 void NGInlineItemsBuilder::Append(NGInlineItem::NGInlineItemType type,
253 UChar character, 284 UChar character,
254 const ComputedStyle* style, 285 const ComputedStyle* style,
(...skipping 25 matching lines...) Expand all
280 return; 311 return;
281 312
282 const ComputedStyle* before_style = after_style; 313 const ComputedStyle* before_style = after_style;
283 if (!items_->IsEmpty()) { 314 if (!items_->IsEmpty()) {
284 NGInlineItem& item = items_->back(); 315 NGInlineItem& item = items_->back();
285 if (text_.length() < item.EndOffset() + 2) 316 if (text_.length() < item.EndOffset() + 2)
286 before_style = item.Style(); 317 before_style = item.Style();
287 } 318 }
288 319
289 if (ShouldRemoveNewline(text_, before_style, after, after_index, after_style)) 320 if (ShouldRemoveNewline(text_, before_style, after, after_index, after_style))
290 RemoveTrailingCollapsibleSpace(next_start_offset); 321 RemoveTrailingCollapsibleSpace(next_start_offset, after_index);
291 } 322 }
292 323
293 void NGInlineItemsBuilder::RemoveTrailingCollapsibleSpaceIfExists( 324 void NGInlineItemsBuilder::RemoveTrailingCollapsibleSpaceIfExists(
294 unsigned* next_start_offset) { 325 unsigned* next_start_offset,
326 unsigned after_index) {
295 if (last_collapsible_space_ != CollapsibleSpace::kNone && !text_.IsEmpty() && 327 if (last_collapsible_space_ != CollapsibleSpace::kNone && !text_.IsEmpty() &&
296 text_[text_.length() - 1] == kSpaceCharacter) 328 text_[text_.length() - 1] == kSpaceCharacter)
297 RemoveTrailingCollapsibleSpace(next_start_offset); 329 RemoveTrailingCollapsibleSpace(next_start_offset, after_index);
298 } 330 }
299 331
300 void NGInlineItemsBuilder::RemoveTrailingCollapsibleSpace( 332 void NGInlineItemsBuilder::RemoveTrailingCollapsibleSpace(
301 unsigned* next_start_offset) { 333 unsigned* next_start_offset,
334 unsigned after_index) {
302 DCHECK_NE(last_collapsible_space_, CollapsibleSpace::kNone); 335 DCHECK_NE(last_collapsible_space_, CollapsibleSpace::kNone);
303 DCHECK(!text_.IsEmpty()); 336 DCHECK(!text_.IsEmpty());
304 DCHECK_EQ(text_[text_.length() - 1], kSpaceCharacter); 337 DCHECK_EQ(text_[text_.length() - 1], kSpaceCharacter);
305 338
306 unsigned new_size = text_.length() - 1; 339 unsigned new_size = text_.length() - 1;
307 text_.Resize(new_size); 340 text_.Resize(new_size);
308 last_collapsible_space_ = CollapsibleSpace::kNone; 341 last_collapsible_space_ = CollapsibleSpace::kNone;
309 342
343 if (collapsed_indexes_)
344 AddLastTrailingSpaceToRemovedIndexes(after_index);
345
310 if (*next_start_offset <= new_size) 346 if (*next_start_offset <= new_size)
311 return; 347 return;
312 *next_start_offset = new_size; 348 *next_start_offset = new_size;
313 349
314 // Adjust the last item if the removed space is already appended. 350 // Adjust the last item if the removed space is already appended.
315 for (unsigned i = items_->size(); i > 0;) { 351 for (unsigned i = items_->size(); i > 0;) {
316 NGInlineItem& item = (*items_)[--i]; 352 NGInlineItem& item = (*items_)[--i];
317 DCHECK_EQ(item.EndOffset(), new_size + 1); 353 DCHECK_EQ(item.EndOffset(), new_size + 1);
318 if (item.Type() == NGInlineItem::kText) { 354 if (item.Type() == NGInlineItem::kText) {
319 DCHECK_GE(item.Length(), 1u); 355 DCHECK_GE(item.Length(), 1u);
320 if (item.Length() > 1) 356 if (item.Length() > 1)
321 item.SetEndOffset(new_size); 357 item.SetEndOffset(new_size);
322 else 358 else
323 items_->erase(i); 359 items_->erase(i);
324 break; 360 break;
325 } 361 }
326 if (!item.Length()) { 362 if (!item.Length()) {
327 // Trailing spaces can be removed across non-character items. 363 // Trailing spaces can be removed across non-character items.
328 item.SetOffset(new_size, new_size); 364 item.SetOffset(new_size, new_size);
329 continue; 365 continue;
330 } 366 }
331 NOTREACHED(); 367 NOTREACHED();
332 break; 368 break;
333 } 369 }
334 } 370 }
335 371
372 void NGInlineItemsBuilder::AddLastTrailingSpaceToRemovedIndexes(
yosin_UTC9 2017/06/20 05:39:09 nit: %s/RemovedIndexes/CollapsedIndexes/
kojii 2017/06/21 09:47:13 This may depend on above, but I can't understand w
Xiaocheng 2017/06/21 18:15:06 This function is called when RemoveTrailingCollaps
373 unsigned last_string_appended_length) {
374 DCHECK(collapsed_indexes_);
375 DCHECK_EQ(collapsed_indexes_->size(), input_strings_lengths_.size());
376 for (unsigned i = collapsed_indexes_->size(); i;) {
377 Vector<unsigned>& indexes = (*collapsed_indexes_)[--i];
378 size_t last_unremoved =
379 GetLargestAbsentInteger(indexes, (i + 1) == collapsed_indexes_->size()
380 ? last_string_appended_length
381 : input_strings_lengths_[i]);
382 if (last_unremoved == kNotFound)
383 continue;
384
385 indexes.insert(
386 std::lower_bound(indexes.begin(), indexes.end(), last_unremoved) -
387 indexes.begin(),
388 last_unremoved);
389 return;
390 }
391 NOTREACHED();
392 }
393
336 void NGInlineItemsBuilder::AppendBidiControl(const ComputedStyle* style, 394 void NGInlineItemsBuilder::AppendBidiControl(const ComputedStyle* style,
337 UChar ltr, 395 UChar ltr,
338 UChar rtl) { 396 UChar rtl) {
339 Append(NGInlineItem::kBidiControl, 397 Append(NGInlineItem::kBidiControl,
340 style->Direction() == TextDirection::kRtl ? rtl : ltr); 398 style->Direction() == TextDirection::kRtl ? rtl : ltr);
341 } 399 }
342 400
343 void NGInlineItemsBuilder::EnterBlock(const ComputedStyle* style) { 401 void NGInlineItemsBuilder::EnterBlock(const ComputedStyle* style) {
344 // Handle bidi-override on the block itself. 402 // Handle bidi-override on the block itself.
345 switch (style->GetUnicodeBidi()) { 403 switch (style->GetUnicodeBidi()) {
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
422 } 480 }
423 481
424 void NGInlineItemsBuilder::Exit(LayoutObject* node) { 482 void NGInlineItemsBuilder::Exit(LayoutObject* node) {
425 while (!exits_.IsEmpty() && exits_.back().node == node) { 483 while (!exits_.IsEmpty() && exits_.back().node == node) {
426 Append(NGInlineItem::kBidiControl, exits_.back().character); 484 Append(NGInlineItem::kBidiControl, exits_.back().character);
427 exits_.pop_back(); 485 exits_.pop_back();
428 } 486 }
429 } 487 }
430 488
431 } // namespace blink 489 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698