Changeset 159194 in webkit
- Timestamp:
- Nov 13, 2013, 7:34:58 AM (11 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r159192 r159194 1 2013-11-13 Antti Koivisto <antti@apple.com> 2 3 Factor simple line creation loop to function 4 https://bugs.webkit.org/show_bug.cgi?id=124279 5 6 Reviewed by Andreas Kling. 7 8 * rendering/SimpleLineLayout.cpp: 9 (WebCore::SimpleLineLayout::Style::Style): 10 11 Capture style that affects line layout to a struct. 12 13 (WebCore::SimpleLineLayout::textWidth): 14 (WebCore::SimpleLineLayout::measureWord): 15 (WebCore::SimpleLineLayout::createLineRuns): 16 17 Factor the line loop here. 18 19 (WebCore::SimpleLineLayout::createTextRuns): 20 1 21 2013-11-12 Antti Koivisto <antti@apple.com> 2 22 -
trunk/Source/WebCore/rendering/SimpleLineLayout.cpp
r159192 r159194 204 204 } 205 205 206 struct Style { 207 Style(const RenderStyle& style) 208 : font(style.font()) 209 , textAlign(style.textAlign()) 210 , collapseWhitespace(style.collapseWhiteSpace()) 211 , preserveNewline(style.preserveNewline()) 212 , wrapLines(style.autoWrap()) 213 , breakWordOnOverflow(style.overflowWrap() == BreakOverflowWrap && (wrapLines || preserveNewline)) 214 , spaceWidth(font.width(TextRun(&space, 1))) 215 , tabWidth(collapseWhitespace ? 0 : style.tabSize()) 216 { 217 } 218 const Font& font; 219 ETextAlign textAlign; 220 bool collapseWhitespace; 221 bool preserveNewline; 222 bool wrapLines; 223 bool breakWordOnOverflow; 224 float spaceWidth; 225 unsigned tabWidth; 226 }; 227 206 228 static inline bool isWhitespace(UChar character, bool preserveNewline) 207 229 { … … 220 242 221 243 template <typename CharacterType> 222 static float textWidth(const RenderText& renderText, const CharacterType* text, unsigned textLength, unsigned from, unsigned to, float xPosition, const Font& font, float tabWidth)223 { 224 if ( font.isFixedPitch() || (!from && to == textLength))225 return renderText.width(from, to - from, font, xPosition, nullptr, nullptr);244 static float textWidth(const RenderText& renderText, const CharacterType* text, unsigned textLength, unsigned from, unsigned to, float xPosition, const Style& style) 245 { 246 if (style.font.isFixedPitch() || (!from && to == textLength)) 247 return renderText.width(from, to - from, style.font, xPosition, nullptr, nullptr); 226 248 227 249 TextRun run(text + from, to - from); 228 250 run.setXPos(xPosition); 229 251 run.setCharactersLength(textLength - from); 230 run.setTabSize(!! tabWidth,tabWidth);252 run.setTabSize(!!style.tabWidth, style.tabWidth); 231 253 232 254 ASSERT(run.charactersLength() >= run.length()); 233 255 234 return font.width(run);235 } 236 237 template <typename CharacterType> 238 static float measureWord( const RenderText& textRenderer, const CharacterType* text, unsigned textLength, unsigned start, unsigned end, float lineWidth, bool collapseWhitespace, const Font& font, float tabWidth, float spaceWidth)256 return style.font.width(run); 257 } 258 259 template <typename CharacterType> 260 static float measureWord(unsigned start, unsigned end, float lineWidth, const Style& style, const CharacterType* text, unsigned textLength, const RenderText& textRenderer) 239 261 { 240 262 if (text[start] == ' ' && end == start + 1) 241 return s paceWidth;242 243 bool measureWithEndSpace = collapseWhitespace && end < textLength && text[end] == ' ';263 return style.spaceWidth; 264 265 bool measureWithEndSpace = style.collapseWhitespace && end < textLength && text[end] == ' '; 244 266 if (measureWithEndSpace) 245 267 ++end; 246 float width = textWidth(textRenderer, text, textLength, start, end, lineWidth, font, collapseWhitespace ? 0 : tabWidth); 247 248 return measureWithEndSpace ? width - spaceWidth : width; 268 float width = textWidth(textRenderer, text, textLength, start, end, lineWidth, style); 269 270 return measureWithEndSpace ? width - style.spaceWidth : width; 271 } 272 273 template <typename CharacterType> 274 Vector<Run, 4> createLineRuns(unsigned lineStart, LineWidth& lineWidth, LazyLineBreakIterator& lineBreakIterator, const Style& style, const CharacterType* text, unsigned textLength, const RenderText& textRenderer) 275 { 276 Vector<Run, 4> lineRuns; 277 lineRuns.uncheckedAppend(Run(lineStart, 0)); 278 279 unsigned wordEnd = lineStart; 280 while (wordEnd < textLength) { 281 ASSERT(!style.collapseWhitespace || !isWhitespace(text[wordEnd], style.preserveNewline)); 282 283 unsigned wordStart = wordEnd; 284 285 if (style.preserveNewline && text[wordStart] == '\n') { 286 ++wordEnd; 287 // FIXME: This creates a dedicated run for newline. This is wasteful and unnecessary but it keeps test results unchanged. 288 if (wordStart > lineStart) 289 lineRuns.append(Run(wordStart, lineRuns.last().right)); 290 lineRuns.last().right = lineRuns.last().left; 291 lineRuns.last().end = wordEnd; 292 break; 293 } 294 295 if (!style.collapseWhitespace && isWhitespace(text[wordStart], style.preserveNewline)) 296 wordEnd = wordStart + 1; 297 else 298 wordEnd = nextBreakablePosition<CharacterType, false>(lineBreakIterator, text, textLength, wordStart + 1); 299 300 bool wordIsPrecededByWhitespace = style.collapseWhitespace && wordStart > lineStart && isWhitespace(text[wordStart - 1], style.preserveNewline); 301 if (wordIsPrecededByWhitespace) 302 --wordStart; 303 304 float wordWidth = measureWord(wordStart, wordEnd, lineWidth.committedWidth(), style, text, textLength, textRenderer); 305 306 lineWidth.addUncommittedWidth(wordWidth); 307 308 if (style.wrapLines) { 309 // Move to the next line if the current one is full and we have something on it. 310 if (!lineWidth.fitsOnLine() && lineWidth.committedWidth()) 311 break; 312 313 // This is for white-space: pre-wrap which requires special handling for end line whitespace. 314 if (!style.collapseWhitespace && lineWidth.fitsOnLine() && wordEnd < textLength && isWhitespace(text[wordEnd], style.preserveNewline)) { 315 // Look ahead to see if the next whitespace would fit. 316 float whitespaceWidth = textWidth(textRenderer, text, textLength, wordEnd, wordEnd + 1, lineWidth.committedWidth(), style); 317 if (!lineWidth.fitsOnLineIncludingExtraWidth(whitespaceWidth)) { 318 // If not eat away the rest of the whitespace on the line. 319 unsigned whitespaceEnd = skipWhitespaces(text, wordEnd, textLength, style.preserveNewline); 320 // Include newline to this run too. 321 if (whitespaceEnd < textLength && text[whitespaceEnd] == '\n') 322 ++whitespaceEnd; 323 lineRuns.last().end = whitespaceEnd; 324 lineRuns.last().right = lineWidth.availableWidth(); 325 break; 326 } 327 } 328 } 329 330 if (wordStart > lineRuns.last().end) { 331 // There were more than one consecutive whitespace. 332 ASSERT(wordIsPrecededByWhitespace); 333 // Include space to the end of the previous run. 334 lineRuns.last().end++; 335 lineRuns.last().right += style.spaceWidth; 336 // Start a new run on the same line. 337 lineRuns.append(Run(wordStart + 1, lineRuns.last().right)); 338 } 339 340 if (!lineWidth.fitsOnLine() && style.breakWordOnOverflow) { 341 // Backtrack and start measuring character-by-character. 342 lineWidth.addUncommittedWidth(-lineWidth.uncommittedWidth()); 343 unsigned splitEnd = wordStart; 344 for (; splitEnd < wordEnd; ++splitEnd) { 345 float charWidth = textWidth(textRenderer, text, textLength, splitEnd, splitEnd + 1, 0, style); 346 lineWidth.addUncommittedWidth(charWidth); 347 if (!lineWidth.fitsOnLine() && splitEnd > lineStart) 348 break; 349 lineWidth.commit(); 350 } 351 lineRuns.last().end = splitEnd; 352 lineRuns.last().right = lineWidth.committedWidth(); 353 // To match line boxes, set single-space-only line width to zero. 354 if (text[lineRuns.last().start] == ' ' && lineRuns.last().start + 1 == lineRuns.last().end) 355 lineRuns.last().right = lineRuns.last().left; 356 break; 357 } 358 359 lineWidth.commit(); 360 361 lineRuns.last().right = lineWidth.committedWidth(); 362 lineRuns.last().end = wordEnd; 363 364 if (style.collapseWhitespace) 365 wordEnd = skipWhitespaces(text, wordEnd, textLength, style.preserveNewline); 366 367 if (!lineWidth.fitsOnLine() && style.wrapLines) { 368 // The first run on the line overflows. 369 ASSERT(lineRuns.size() == 1); 370 break; 371 } 372 } 373 return lineRuns; 249 374 } 250 375 … … 283 408 void createTextRuns(Layout::RunVector& runs, unsigned& lineCount, RenderBlockFlow& flow, RenderText& textRenderer) 284 409 { 285 const RenderStyle& style = flow.style(); 286 287 // These properties are supported. 288 const Font& font = style.font(); 289 unsigned tabWidth = style.tabSize(); 290 ETextAlign textAlign = style.textAlign(); // Not 'justify'. 291 bool collapseWhitespace = style.collapseWhiteSpace(); 292 bool preserveNewline = style.preserveNewline(); 293 bool wrapLines = style.autoWrap(); 294 bool breakWordOnOverflow = style.overflowWrap() == BreakOverflowWrap && (wrapLines || preserveNewline); 410 const Style style(flow.style()); 295 411 296 412 const CharacterType* text = textRenderer.text()->getCharacters<CharacterType>(); 297 413 const unsigned textLength = textRenderer.textLength(); 298 414 299 float spaceWidth = font.width(TextRun(&space, 1)); 300 LazyLineBreakIterator lineBreakIterator(textRenderer.text(), style.locale()); 415 LazyLineBreakIterator lineBreakIterator(textRenderer.text(), flow.style().locale()); 301 416 302 417 unsigned lineEnd = 0; 303 418 while (lineEnd < textLength) { 304 if (collapseWhitespace) 305 lineEnd = skipWhitespaces(text, lineEnd, textLength, preserveNewline); 419 if (style.collapseWhitespace) 420 lineEnd = skipWhitespaces(text, lineEnd, textLength, style.preserveNewline); 421 306 422 unsigned lineStart = lineEnd; 307 unsigned wordEnd = lineEnd; 423 308 424 LineWidth lineWidth(flow, false, DoNotIndentText); 309 310 Vector<Run, 4> lineRuns; 311 lineRuns.uncheckedAppend(Run(lineStart, 0)); 312 313 while (wordEnd < textLength) { 314 ASSERT(!collapseWhitespace || !isWhitespace(text[wordEnd], preserveNewline)); 315 316 unsigned wordStart = wordEnd; 317 318 if (preserveNewline && text[wordStart] == '\n') { 319 ++wordEnd; 320 // FIXME: This creates a dedicated run for newline. This is wasteful and unnecessary but it keeps test results unchanged. 321 if (wordStart > lineStart) 322 lineRuns.append(Run(lineEnd, lineRuns.last().right)); 323 lineRuns.last().right = lineRuns.last().left; 324 lineRuns.last().end = lineEnd + 1; 325 lineEnd = wordEnd; 326 break; 327 } 328 329 if (!collapseWhitespace && isWhitespace(text[wordStart], preserveNewline)) 330 wordEnd = wordStart + 1; 331 else 332 wordEnd = nextBreakablePosition<CharacterType, false>(lineBreakIterator, text, textLength, wordStart + 1); 333 334 bool wordIsPrecededByWhitespace = collapseWhitespace && wordStart > lineStart && isWhitespace(text[wordStart - 1], preserveNewline); 335 if (wordIsPrecededByWhitespace) 336 --wordStart; 337 338 float wordWidth = measureWord(textRenderer, text, textLength, wordStart, wordEnd, lineWidth.committedWidth(), collapseWhitespace, font, tabWidth, spaceWidth); 339 340 lineWidth.addUncommittedWidth(wordWidth); 341 342 if (wrapLines) { 343 // Move to the next line if the current one is full and we have something on it. 344 if (!lineWidth.fitsOnLine() && lineWidth.committedWidth()) 345 break; 346 347 // This is for white-space: pre-wrap which requires special handling for end line whitespace. 348 if (!collapseWhitespace && lineWidth.fitsOnLine() && wordEnd < textLength && isWhitespace(text[wordEnd], preserveNewline)) { 349 // Look ahead to see if the next whitespace would fit. 350 float whitespaceWidth = textWidth(textRenderer, text, textLength, wordEnd, wordEnd + 1, lineWidth.committedWidth(), font, tabWidth); 351 if (!lineWidth.fitsOnLineIncludingExtraWidth(whitespaceWidth)) { 352 // If not eat away the rest of the whitespace on the line. 353 unsigned whitespaceEnd = skipWhitespaces(text, wordEnd, textLength, preserveNewline); 354 // Include newline to this run too. 355 if (whitespaceEnd < textLength && text[whitespaceEnd] == '\n') 356 ++whitespaceEnd; 357 lineRuns.last().end = whitespaceEnd; 358 lineRuns.last().right = lineWidth.availableWidth(); 359 lineEnd = whitespaceEnd; 360 break; 361 } 362 } 363 } 364 365 if (wordStart > lineEnd) { 366 // There were more than one consecutive whitespace. 367 ASSERT(wordIsPrecededByWhitespace); 368 // Include space to the end of the previous run. 369 lineRuns.last().end++; 370 lineRuns.last().right += spaceWidth; 371 // Start a new run on the same line. 372 lineRuns.append(Run(wordStart + 1, lineRuns.last().right)); 373 } 374 375 if (!lineWidth.fitsOnLine() && breakWordOnOverflow) { 376 // Backtrack and start measuring character-by-character. 377 lineWidth.addUncommittedWidth(-lineWidth.uncommittedWidth()); 378 unsigned splitEnd = wordStart; 379 for (; splitEnd < wordEnd; ++splitEnd) { 380 float charWidth = textWidth(textRenderer, text, textLength, splitEnd, splitEnd + 1, 0, font, tabWidth); 381 lineWidth.addUncommittedWidth(charWidth); 382 if (!lineWidth.fitsOnLine() && splitEnd > lineStart) 383 break; 384 lineWidth.commit(); 385 } 386 lineRuns.last().end = splitEnd; 387 lineRuns.last().right = lineWidth.committedWidth(); 388 lineEnd = splitEnd; 389 // To match line boxes, set single-space-only line width to zero. 390 if (text[lineRuns.last().start] == ' ' && lineRuns.last().start + 1 == lineRuns.last().end) 391 lineRuns.last().right = lineRuns.last().left; 392 break; 393 } 394 395 lineWidth.commit(); 396 397 lineRuns.last().right = lineWidth.committedWidth(); 398 lineRuns.last().end = wordEnd; 399 400 lineEnd = wordEnd; 401 if (collapseWhitespace) 402 wordEnd = skipWhitespaces(text, wordEnd, textLength, preserveNewline); 403 404 if (!lineWidth.fitsOnLine() && wrapLines) { 405 // The first run on the line overflows. 406 ASSERT(lineRuns.size() == 1); 407 break; 408 } 409 } 425 auto lineRuns = createLineRuns(lineStart, lineWidth, lineBreakIterator, style, text, textLength, textRenderer); 426 427 lineEnd = lineRuns.last().end; 410 428 if (lineStart == lineEnd) 411 429 continue; … … 413 431 lineRuns.last().isEndOfLine = true; 414 432 415 float lineLeft = computeLineLeft( textAlign, lineWidth.availableWidth() - lineWidth.committedWidth());433 float lineLeft = computeLineLeft(style.textAlign, lineWidth.availableWidth() - lineWidth.committedWidth()); 416 434 adjustRunOffsets(lineRuns, lineLeft); 417 435
Note:
See TracChangeset
for help on using the changeset viewer.