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

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: Add documentation 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(
14 Vector<NGInlineItem>* items,
15 Vector<Vector<unsigned>>* removed_indexes)
16 : items_(items),
17 removed_indexes_(removed_indexes),
18 input_strings_lengths_(Vector<unsigned>()) {
19 DCHECK(removed_indexes);
20 }
21
13 NGInlineItemsBuilder::~NGInlineItemsBuilder() { 22 NGInlineItemsBuilder::~NGInlineItemsBuilder() {
14 DCHECK_EQ(0u, exits_.size()); 23 DCHECK_EQ(0u, exits_.size());
15 DCHECK_EQ(text_.length(), items_->IsEmpty() ? 0 : items_->back().EndOffset()); 24 DCHECK_EQ(text_.length(), items_->IsEmpty() ? 0 : items_->back().EndOffset());
16 } 25 }
17 26
18 String NGInlineItemsBuilder::ToString() { 27 String NGInlineItemsBuilder::ToString() {
19 // Segment Break Transformation Rules[1] defines to keep trailing new lines, 28 // 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 29 // but it will be removed in Phase II[2]. We prefer not to add trailing new
21 // lines and collapsible spaces in Phase I. 30 // lines and collapsible spaces in Phase I.
22 // [1] https://drafts.csswg.org/css-text-3/#line-break-transform 31 // [1] https://drafts.csswg.org/css-text-3/#line-break-transform
23 // [2] https://drafts.csswg.org/css-text-3/#white-space-phase-2 32 // [2] https://drafts.csswg.org/css-text-3/#white-space-phase-2
24 unsigned next_start_offset = text_.length(); 33 unsigned next_start_offset = text_.length();
25 RemoveTrailingCollapsibleSpaceIfExists(&next_start_offset); 34 bool trailing_space_removed =
35 RemoveTrailingCollapsibleSpaceIfExists(&next_start_offset);
36 if (trailing_space_removed && removed_indexes_) {
37 DCHECK(input_strings_lengths_);
38 AddLastTrailingSpaceToRemovedIndexes(input_strings_lengths_->back());
39 }
26 40
27 return text_.ToString(); 41 return text_.ToString();
28 } 42 }
29 43
30 // Determine "Ambiguous" East Asian Width is Wide or Narrow. 44 // Determine "Ambiguous" East Asian Width is Wide or Narrow.
31 // Unicode East Asian Width 45 // Unicode East Asian Width
32 // http://unicode.org/reports/tr11/ 46 // http://unicode.org/reports/tr11/
33 static bool IsAmbiguosEastAsianWidthWide(const ComputedStyle* style) { 47 static bool IsAmbiguosEastAsianWidthWide(const ComputedStyle* style) {
34 UScriptCode script = style->GetFontDescription().GetScript(); 48 UScriptCode script = style->GetFontDescription().GetScript();
35 return script == USCRIPT_KATAKANA_OR_HIRAGANA || 49 return script == USCRIPT_KATAKANA_OR_HIRAGANA ||
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
117 return c == kSpaceCharacter || c == kTabulationCharacter || 131 return c == kSpaceCharacter || c == kTabulationCharacter ||
118 c == kNewlineCharacter; 132 c == kNewlineCharacter;
119 } 133 }
120 134
121 // Characters needing a separate control item than other text items. 135 // Characters needing a separate control item than other text items.
122 // It makes the line breaker easier to handle. 136 // It makes the line breaker easier to handle.
123 static inline bool IsControlItemCharacter(UChar c) { 137 static inline bool IsControlItemCharacter(UChar c) {
124 return c == kTabulationCharacter || c == kNewlineCharacter; 138 return c == kTabulationCharacter || c == kNewlineCharacter;
125 } 139 }
126 140
141 // Returns the largest integer in [0, |max|) that is absent in |integers|, or
142 // kNotFound if such an integer does not exist.
143 static size_t GetLargestAbsentInteger(const Vector<unsigned>& integers,
144 unsigned max) {
145 DCHECK(integers.IsEmpty() || integers.back() < max);
146 if (!max || integers.size() == max)
147 return kNotFound;
148 if (integers.IsEmpty() || integers.back() + 1 < max)
149 return max - 1;
150 for (unsigned i = integers.size() - 1; i;) {
151 DCHECK_LT(integers[i - 1], integers[i]);
152 if (integers[i - 1] + 1 < integers[i] - 1)
153 return integers[i] - 1;
154 --i;
155 }
156 DCHECK_GT(integers[0], 0u);
157 return integers[0] - 1;
158 }
159
127 void NGInlineItemsBuilder::Append(const String& string, 160 void NGInlineItemsBuilder::Append(const String& string,
128 const ComputedStyle* style, 161 const ComputedStyle* style,
129 LayoutObject* layout_object) { 162 LayoutObject* layout_object) {
163 if (removed_indexes_) {
164 DCHECK(input_strings_lengths_);
165 input_strings_lengths_->push_back(string.length());
166 removed_indexes_->emplace_back();
167 }
168
130 if (string.IsEmpty()) 169 if (string.IsEmpty())
131 return; 170 return;
132 text_.ReserveCapacity(string.length()); 171 text_.ReserveCapacity(string.length());
133 172
134 EWhiteSpace whitespace = style->WhiteSpace(); 173 EWhiteSpace whitespace = style->WhiteSpace();
135 if (!ComputedStyle::CollapseWhiteSpace(whitespace)) 174 if (!ComputedStyle::CollapseWhiteSpace(whitespace))
136 return AppendWithoutWhiteSpaceCollapsing(string, style, layout_object); 175 return AppendWithoutWhiteSpaceCollapsing(string, style, layout_object);
137 if (ComputedStyle::PreserveNewline(whitespace) && !is_svgtext_) 176 if (ComputedStyle::PreserveNewline(whitespace) && !is_svgtext_)
138 return AppendWithPreservingNewlines(string, style, layout_object); 177 return AppendWithPreservingNewlines(string, style, layout_object);
139 178
140 AppendWithWhiteSpaceCollapsing(string, 0, string.length(), style, 179 AppendWithWhiteSpaceCollapsing(string, 0, string.length(), style,
141 layout_object); 180 layout_object);
142 } 181 }
143 182
144 void NGInlineItemsBuilder::AppendWithWhiteSpaceCollapsing( 183 void NGInlineItemsBuilder::AppendWithWhiteSpaceCollapsing(
145 const String& string, 184 const String& string,
146 unsigned start, 185 unsigned start,
147 unsigned end, 186 unsigned end,
148 const ComputedStyle* style, 187 const ComputedStyle* style,
149 LayoutObject* layout_object) { 188 LayoutObject* layout_object) {
150 unsigned start_offset = text_.length(); 189 unsigned start_offset = text_.length();
151 for (unsigned i = start; i < end;) { 190 for (unsigned i = start; i < end;) {
152 UChar c = string[i]; 191 UChar c = string[i];
153 if (c == kNewlineCharacter) { 192 if (c == kNewlineCharacter) {
154 // LayoutBR does not set preserve_newline, but should be preserved. 193 // LayoutBR does not set preserve_newline, but should be preserved.
155 if (!i && end == 1 && layout_object && layout_object->IsBR()) { 194 if (!i && end == 1 && layout_object && layout_object->IsBR()) {
156 AppendForcedBreak(style, layout_object); 195 bool trailing_space_removed = AppendForcedBreak(style, layout_object);
196 if (trailing_space_removed && removed_indexes_)
197 AddLastTrailingSpaceToRemovedIndexes(i);
kojii 2017/06/19 05:56:33 Why don't we add to removed_indexes in RemoveTrail
Xiaocheng 2017/06/19 17:53:01 Updating |removed_indexes_| needs the number of ch
157 return; 198 return;
158 } 199 }
159 200
160 if (last_collapsible_space_ == CollapsibleSpace::kNone) 201 if (last_collapsible_space_ == CollapsibleSpace::kNone)
161 text_.Append(kSpaceCharacter); 202 text_.Append(kSpaceCharacter);
203 else if (removed_indexes_)
204 removed_indexes_->back().push_back(i);
162 last_collapsible_space_ = CollapsibleSpace::kNewline; 205 last_collapsible_space_ = CollapsibleSpace::kNewline;
163 i++; 206 i++;
164 continue; 207 continue;
165 } 208 }
166 209
167 if (c == kSpaceCharacter || c == kTabulationCharacter) { 210 if (c == kSpaceCharacter || c == kTabulationCharacter) {
168 if (last_collapsible_space_ == CollapsibleSpace::kNone) { 211 if (last_collapsible_space_ == CollapsibleSpace::kNone) {
169 text_.Append(kSpaceCharacter); 212 text_.Append(kSpaceCharacter);
170 last_collapsible_space_ = CollapsibleSpace::kSpace; 213 last_collapsible_space_ = CollapsibleSpace::kSpace;
214 } else if (removed_indexes_) {
215 removed_indexes_->back().push_back(i);
171 } 216 }
172 i++; 217 i++;
173 continue; 218 continue;
174 } 219 }
175 220
176 if (last_collapsible_space_ == CollapsibleSpace::kNewline) { 221 if (last_collapsible_space_ == CollapsibleSpace::kNewline) {
177 RemoveTrailingCollapsibleNewlineIfNeeded(&start_offset, string, i, style); 222 bool trailing_newline_removed = RemoveTrailingCollapsibleNewlineIfNeeded(
223 &start_offset, string, i, style);
224 if (trailing_newline_removed && removed_indexes_)
225 AddLastTrailingSpaceToRemovedIndexes(i);
178 } 226 }
179 227
180 size_t end_of_non_space = string.Find(IsCollapsibleSpace, i + 1); 228 size_t end_of_non_space = string.Find(IsCollapsibleSpace, i + 1);
181 if (end_of_non_space == kNotFound) 229 if (end_of_non_space == kNotFound)
182 end_of_non_space = string.length(); 230 end_of_non_space = string.length();
183 text_.Append(string, i, end_of_non_space - i); 231 text_.Append(string, i, end_of_non_space - i);
184 i = end_of_non_space; 232 i = end_of_non_space;
185 last_collapsible_space_ = CollapsibleSpace::kNone; 233 last_collapsible_space_ = CollapsibleSpace::kNone;
186 } 234 }
187 235
(...skipping 29 matching lines...) Expand all
217 265
218 last_collapsible_space_ = CollapsibleSpace::kNone; 266 last_collapsible_space_ = CollapsibleSpace::kNone;
219 } 267 }
220 268
221 void NGInlineItemsBuilder::AppendWithPreservingNewlines( 269 void NGInlineItemsBuilder::AppendWithPreservingNewlines(
222 const String& string, 270 const String& string,
223 const ComputedStyle* style, 271 const ComputedStyle* style,
224 LayoutObject* layout_object) { 272 LayoutObject* layout_object) {
225 for (unsigned start = 0; start < string.length();) { 273 for (unsigned start = 0; start < string.length();) {
226 if (string[start] == kNewlineCharacter) { 274 if (string[start] == kNewlineCharacter) {
227 AppendForcedBreak(style, layout_object); 275 bool trailing_space_removed = AppendForcedBreak(style, layout_object);
276 if (trailing_space_removed && removed_indexes_)
277 AddLastTrailingSpaceToRemovedIndexes(start);
228 start++; 278 start++;
229 continue; 279 continue;
230 } 280 }
231 281
232 size_t end = string.find(kNewlineCharacter, start + 1); 282 size_t end = string.find(kNewlineCharacter, start + 1);
233 if (end == kNotFound) 283 if (end == kNotFound)
234 end = string.length(); 284 end = string.length();
235 AppendWithWhiteSpaceCollapsing(string, start, end, style, layout_object); 285 AppendWithWhiteSpaceCollapsing(string, start, end, style, layout_object);
236 start = end; 286 start = end;
237 } 287 }
238 } 288 }
239 289
240 void NGInlineItemsBuilder::AppendForcedBreak(const ComputedStyle* style, 290 bool NGInlineItemsBuilder::AppendForcedBreak(const ComputedStyle* style,
241 LayoutObject* layout_object) { 291 LayoutObject* layout_object) {
242 // Remove collapsible spaces immediately before a preserved newline. 292 // Remove collapsible spaces immediately before a preserved newline.
243 unsigned start_offset = text_.length(); 293 unsigned start_offset = text_.length();
244 RemoveTrailingCollapsibleSpaceIfExists(&start_offset); 294 bool trailing_space_removed =
295 RemoveTrailingCollapsibleSpaceIfExists(&start_offset);
245 296
246 Append(NGInlineItem::kControl, kNewlineCharacter, style, layout_object); 297 Append(NGInlineItem::kControl, kNewlineCharacter, style, layout_object);
247 298
248 // Remove collapsible spaces immediately after a preserved newline. 299 // Remove collapsible spaces immediately after a preserved newline.
249 last_collapsible_space_ = CollapsibleSpace::kSpace; 300 last_collapsible_space_ = CollapsibleSpace::kSpace;
301 return trailing_space_removed;
250 } 302 }
251 303
252 void NGInlineItemsBuilder::Append(NGInlineItem::NGInlineItemType type, 304 void NGInlineItemsBuilder::Append(NGInlineItem::NGInlineItemType type,
253 UChar character, 305 UChar character,
254 const ComputedStyle* style, 306 const ComputedStyle* style,
255 LayoutObject* layout_object) { 307 LayoutObject* layout_object) {
256 DCHECK_NE(character, kSpaceCharacter); 308 DCHECK_NE(character, kSpaceCharacter);
257 DCHECK_NE(character, kZeroWidthSpaceCharacter); 309 DCHECK_NE(character, kZeroWidthSpaceCharacter);
258 310
259 text_.Append(character); 311 text_.Append(character);
260 unsigned end_offset = text_.length(); 312 unsigned end_offset = text_.length();
261 AppendItem(items_, type, end_offset - 1, end_offset, style, layout_object); 313 AppendItem(items_, type, end_offset - 1, end_offset, style, layout_object);
262 last_collapsible_space_ = CollapsibleSpace::kNone; 314 last_collapsible_space_ = CollapsibleSpace::kNone;
263 } 315 }
264 316
265 void NGInlineItemsBuilder::Append(NGInlineItem::NGInlineItemType type, 317 void NGInlineItemsBuilder::Append(NGInlineItem::NGInlineItemType type,
266 const ComputedStyle* style, 318 const ComputedStyle* style,
267 LayoutObject* layout_object) { 319 LayoutObject* layout_object) {
268 unsigned end_offset = text_.length(); 320 unsigned end_offset = text_.length();
269 AppendItem(items_, type, end_offset, end_offset, style, layout_object); 321 AppendItem(items_, type, end_offset, end_offset, style, layout_object);
270 } 322 }
271 323
272 void NGInlineItemsBuilder::RemoveTrailingCollapsibleNewlineIfNeeded( 324 bool NGInlineItemsBuilder::RemoveTrailingCollapsibleNewlineIfNeeded(
273 unsigned* next_start_offset, 325 unsigned* next_start_offset,
274 const String& after, 326 const String& after,
275 unsigned after_index, 327 unsigned after_index,
276 const ComputedStyle* after_style) { 328 const ComputedStyle* after_style) {
277 DCHECK_EQ(last_collapsible_space_, CollapsibleSpace::kNewline); 329 DCHECK_EQ(last_collapsible_space_, CollapsibleSpace::kNewline);
278 330
279 if (text_.IsEmpty() || text_[text_.length() - 1] != kSpaceCharacter) 331 if (text_.IsEmpty() || text_[text_.length() - 1] != kSpaceCharacter)
280 return; 332 return false;
281 333
282 const ComputedStyle* before_style = after_style; 334 const ComputedStyle* before_style = after_style;
283 if (!items_->IsEmpty()) { 335 if (!items_->IsEmpty()) {
284 NGInlineItem& item = items_->back(); 336 NGInlineItem& item = items_->back();
285 if (text_.length() < item.EndOffset() + 2) 337 if (text_.length() < item.EndOffset() + 2)
286 before_style = item.Style(); 338 before_style = item.Style();
287 } 339 }
288 340
289 if (ShouldRemoveNewline(text_, before_style, after, after_index, after_style)) 341 if (!ShouldRemoveNewline(text_, before_style, after, after_index,
290 RemoveTrailingCollapsibleSpace(next_start_offset); 342 after_style))
343 return false;
344 RemoveTrailingCollapsibleSpace(next_start_offset);
345 return true;
291 } 346 }
292 347
293 void NGInlineItemsBuilder::RemoveTrailingCollapsibleSpaceIfExists( 348 bool NGInlineItemsBuilder::RemoveTrailingCollapsibleSpaceIfExists(
294 unsigned* next_start_offset) { 349 unsigned* next_start_offset) {
295 if (last_collapsible_space_ != CollapsibleSpace::kNone && !text_.IsEmpty() && 350 if (last_collapsible_space_ == CollapsibleSpace::kNone || text_.IsEmpty() ||
296 text_[text_.length() - 1] == kSpaceCharacter) 351 text_[text_.length() - 1] != kSpaceCharacter)
297 RemoveTrailingCollapsibleSpace(next_start_offset); 352 return false;
353 RemoveTrailingCollapsibleSpace(next_start_offset);
354 return true;
298 } 355 }
299 356
300 void NGInlineItemsBuilder::RemoveTrailingCollapsibleSpace( 357 void NGInlineItemsBuilder::RemoveTrailingCollapsibleSpace(
301 unsigned* next_start_offset) { 358 unsigned* next_start_offset) {
302 DCHECK_NE(last_collapsible_space_, CollapsibleSpace::kNone); 359 DCHECK_NE(last_collapsible_space_, CollapsibleSpace::kNone);
303 DCHECK(!text_.IsEmpty()); 360 DCHECK(!text_.IsEmpty());
304 DCHECK_EQ(text_[text_.length() - 1], kSpaceCharacter); 361 DCHECK_EQ(text_[text_.length() - 1], kSpaceCharacter);
305 362
306 unsigned new_size = text_.length() - 1; 363 unsigned new_size = text_.length() - 1;
307 text_.Resize(new_size); 364 text_.Resize(new_size);
(...skipping 18 matching lines...) Expand all
326 if (!item.Length()) { 383 if (!item.Length()) {
327 // Trailing spaces can be removed across non-character items. 384 // Trailing spaces can be removed across non-character items.
328 item.SetOffset(new_size, new_size); 385 item.SetOffset(new_size, new_size);
329 continue; 386 continue;
330 } 387 }
331 NOTREACHED(); 388 NOTREACHED();
332 break; 389 break;
333 } 390 }
334 } 391 }
335 392
393 void NGInlineItemsBuilder::AddLastTrailingSpaceToRemovedIndexes(
394 unsigned last_string_end) {
395 DCHECK(removed_indexes_);
396 DCHECK(input_strings_lengths_);
397 DCHECK_EQ(removed_indexes_->size(), input_strings_lengths_->size());
398 for (unsigned i = removed_indexes_->size(); i;) {
399 Vector<unsigned>& indexes = (*removed_indexes_)[--i];
400 size_t last_unremoved =
401 GetLargestAbsentInteger(indexes, (i + 1) == removed_indexes_->size()
402 ? last_string_end
403 : (*input_strings_lengths_)[i]);
404 if (last_unremoved == kNotFound)
405 continue;
406
407 indexes.insert(
408 std::lower_bound(indexes.begin(), indexes.end(), last_unremoved) -
409 indexes.begin(),
410 last_unremoved);
411 return;
412 }
413 NOTREACHED();
414 }
415
336 void NGInlineItemsBuilder::AppendBidiControl(const ComputedStyle* style, 416 void NGInlineItemsBuilder::AppendBidiControl(const ComputedStyle* style,
337 UChar ltr, 417 UChar ltr,
338 UChar rtl) { 418 UChar rtl) {
339 Append(NGInlineItem::kBidiControl, 419 Append(NGInlineItem::kBidiControl,
340 style->Direction() == TextDirection::kRtl ? rtl : ltr); 420 style->Direction() == TextDirection::kRtl ? rtl : ltr);
341 } 421 }
342 422
343 void NGInlineItemsBuilder::EnterBlock(const ComputedStyle* style) { 423 void NGInlineItemsBuilder::EnterBlock(const ComputedStyle* style) {
344 // Handle bidi-override on the block itself. 424 // Handle bidi-override on the block itself.
345 switch (style->GetUnicodeBidi()) { 425 switch (style->GetUnicodeBidi()) {
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
422 } 502 }
423 503
424 void NGInlineItemsBuilder::Exit(LayoutObject* node) { 504 void NGInlineItemsBuilder::Exit(LayoutObject* node) {
425 while (!exits_.IsEmpty() && exits_.back().node == node) { 505 while (!exits_.IsEmpty() && exits_.back().node == node) {
426 Append(NGInlineItem::kBidiControl, exits_.back().character); 506 Append(NGInlineItem::kBidiControl, exits_.back().character);
427 exits_.pop_back(); 507 exits_.pop_back();
428 } 508 }
429 } 509 }
430 510
431 } // namespace blink 511 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698