Changeset 175565 in webkit
- Timestamp:
- Nov 4, 2014 12:08:13 PM (9 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r175564 r175565 1 2014-11-04 Zalan Bujtas <zalan@apple.com> 2 3 Simple line layout: Cleanup line initialization and line closing. 4 https://bugs.webkit.org/show_bug.cgi?id=138273 5 6 Reviewed by Antti Koivisto. 7 8 This is in preparation to support multiple render elements. 9 10 Move line start and line end activities to dedicated functions. 11 12 Covered by existing tests. 13 14 * rendering/SimpleLineLayout.cpp: 15 (WebCore::SimpleLineLayout::LineState::LineState): Add lineStartRunIndex to be more explicit 16 about whether a line advanced with new runs. Rename a few members. Introduce LineState::oveflowedFragment 17 so that line closing can handled separately. 18 (WebCore::SimpleLineLayout::LineState::commitAndCreateRun): 19 (WebCore::SimpleLineLayout::LineState::addUncommitted): 20 (WebCore::SimpleLineLayout::LineState::jumpTo): 21 (WebCore::SimpleLineLayout::LineState::addUncommittedWhitespace): Deleted. : Remove redundant function. 22 (WebCore::SimpleLineLayout::LineState::removeCommittedTrailingWhitespace): 23 (WebCore::SimpleLineLayout::LineState::resetTrailingWhitespace): 24 (WebCore::SimpleLineLayout::removeTrailingWhitespace): Add resetTrailingWhitespace() 25 so that all trailing whitespace handling is in one function. 26 (WebCore::SimpleLineLayout::initializeNewLine): Separate line start and line end initialization/reset. 27 (WebCore::SimpleLineLayout::createLineRuns): 28 (WebCore::SimpleLineLayout::closeLineEndingAndAdjustRuns): This function manages all line ending activities. 29 (WebCore::SimpleLineLayout::createTextRuns): 30 (WebCore::SimpleLineLayout::create): 31 (WebCore::SimpleLineLayout::initializeLine): Deleted. 32 * rendering/SimpleLineLayout.h: 33 (WebCore::SimpleLineLayout::Run::Run): Deleted. 34 1 35 2014-11-04 Tim Horton <timothy_horton@apple.com> 2 36 -
trunk/Source/WebCore/rendering/SimpleLineLayout.cpp
r175259 r175565 278 278 { } 279 279 280 TextFragment(unsigned textStart, unsigned textEnd, unsigned textWidth)280 TextFragment(unsigned textStart, unsigned textEnd, float textWidth, bool isWhitespaceOnly) 281 281 : start(textStart) 282 282 , isCollapsedWhitespace(false) 283 283 , end(textEnd) 284 , isWhitespaceOnly( false)284 , isWhitespaceOnly(isWhitespaceOnly) 285 285 , isBreakable(false) 286 286 , mustBreak(false) … … 306 306 : availableWidth(0) 307 307 , logicalLeftOffset(0) 308 , lineStartRunIndex(0) 308 309 , uncommittedStart(0) 309 310 , uncommittedEnd(0) 310 , uncommittedLeft(0)311 311 , uncommittedWidth(0) 312 312 , committedWidth(0) 313 , end(0) 313 , committedLogicalRight(0) 314 , position(0) 314 315 , trailingWhitespaceWidth(0) 315 316 { … … 321 322 return; 322 323 323 lineRuns.append(Run(uncommittedStart, uncommittedEnd, uncommittedLeft, uncommittedLeft + uncommittedWidth, false));324 lineRuns.append(Run(uncommittedStart, uncommittedEnd, committedLogicalRight, committedLogicalRight + uncommittedWidth, false)); 324 325 // Move uncommitted to committed. 325 326 committedWidth += uncommittedWidth; 327 committedLogicalRight += committedWidth; 326 328 327 329 uncommittedStart = uncommittedEnd; 328 uncommittedLeft += uncommittedWidth;329 330 uncommittedWidth = 0; 330 331 } … … 332 333 void addUncommitted(const TextFragment& fragment) 333 334 { 334 addUncommitted(fragment.end, fragment.width, fragment.isWhitespaceOnly); 335 } 336 337 void addUncommitted(unsigned fragmentEnd, float fragmentWidth, bool whitespaceOnly) 338 { 339 unsigned uncomittedFragmentLength = fragmentEnd - uncommittedEnd; 340 uncommittedWidth += fragmentWidth; 341 uncommittedEnd = fragmentEnd; 342 end = uncommittedEnd; 343 trailingWhitespaceWidth = whitespaceOnly ? fragmentWidth : 0; 344 trailingWhitespaceLength = whitespaceOnly ? uncomittedFragmentLength : 0; 335 unsigned uncomittedFragmentLength = fragment.end - uncommittedEnd; 336 uncommittedWidth += fragment.width; 337 uncommittedEnd = fragment.end; 338 position = uncommittedEnd; 339 trailingWhitespaceWidth = fragment.isWhitespaceOnly ? fragment.width : 0; 340 trailingWhitespaceLength = fragment.isWhitespaceOnly ? uncomittedFragmentLength : 0; 345 341 } 346 342 347 343 void addUncommittedWhitespace(float whitespaceWidth) 348 344 { 349 addUncommitted( uncommittedEnd + 1, whitespaceWidth, true);350 } 351 352 void jumpTo(unsigned newPositon, float l eftX)353 { 354 end= newPositon;345 addUncommitted(TextFragment(uncommittedEnd, uncommittedEnd + 1, whitespaceWidth, true)); 346 } 347 348 void jumpTo(unsigned newPositon, float logicalRight) 349 { 350 position = newPositon; 355 351 356 352 uncommittedStart = newPositon; 357 353 uncommittedEnd = newPositon; 358 uncommittedLeft = leftX;359 354 uncommittedWidth = 0; 355 committedLogicalRight = logicalRight; 360 356 } 361 357 … … 374 370 ASSERT(!uncommittedWidth); 375 371 committedWidth -= trailingWhitespaceWidth; 372 committedLogicalRight -= trailingWhitespaceWidth; 373 } 374 375 void resetTrailingWhitespace() 376 { 376 377 trailingWhitespaceWidth = 0; 377 378 trailingWhitespaceLength = 0; … … 380 381 float availableWidth; 381 382 float logicalLeftOffset; 383 unsigned lineStartRunIndex; // The run that the line starts with. 382 384 383 385 unsigned uncommittedStart; 384 386 unsigned uncommittedEnd; 385 float uncommittedLeft;386 387 float uncommittedWidth; 387 388 float committedWidth; 388 unsigned end; // End position of the current line. 389 float committedLogicalRight; // Last committed X (coordinate) position. 390 391 unsigned position; 392 389 393 float trailingWhitespaceWidth; // Use this to remove trailing whitespace without re-mesuring the text. 390 394 float trailingWhitespaceLength; 395 396 TextFragment oveflowedFragment; 391 397 }; 392 398 393 399 template <typename CharacterType> 394 static void removeTrailingWhitespace(LineState& line , TextFragment& fragmentForNextLine, Layout::RunVector& lineRuns, const Style& style, const CharacterType* text, unsigned textLength)400 static void removeTrailingWhitespace(LineState& lineState, Layout::RunVector& lineRuns, const Style& style, const CharacterType* text, unsigned textLength) 395 401 { 396 402 bool preWrap = style.wrapLines && !style.collapseWhitespace; 397 403 // Trailing whitespace gets removed when we either collapse whitespace or pre-wrap is present. 398 if (!(style.collapseWhitespace || preWrap)) 404 if (!(style.collapseWhitespace || preWrap)) { 405 lineState.resetTrailingWhitespace(); 399 406 return; 407 } 400 408 401 409 ASSERT(lineRuns.size()); 402 410 Run& lastRun = lineRuns.last(); 403 411 404 unsigned originalLineEnd = line.end;412 unsigned lastPosition = lineState.position; 405 413 bool trailingPreWrapWhitespaceNeedsToBeRemoved = false; 406 414 // When pre-wrap is present, trailing whitespace needs to be removed: 407 // 1. from the "next line": when at least the first charater fits. When even the first whitespace is wider that the available width, we don't remove any whitespace at all. 415 // 1. from the "next line": when at least the first charater fits. When even the first whitespace is wider that the available width, 416 // we don't remove any whitespace at all. 408 417 // 2. from this line: remove whitespace, unless it's the only fragment on the line -so removing the whitesapce would produce an empty line. 409 418 if (preWrap) { 410 if ( fragmentForNextLine.isWhitespaceOnly && !fragmentForNextLine.isEmpty() && line.availableWidth >= line.committedWidth) {411 line .end = fragmentForNextLine.end;412 fragmentForNextLine= TextFragment();419 if (lineState.oveflowedFragment.isWhitespaceOnly && !lineState.oveflowedFragment.isEmpty() && lineState.availableWidth >= lineState.committedWidth) { 420 lineState.position = lineState.oveflowedFragment.end; 421 lineState.oveflowedFragment = TextFragment(); 413 422 } 414 if (line.trailingWhitespaceLength) 415 trailingPreWrapWhitespaceNeedsToBeRemoved = !(line.committedWidth == line.trailingWhitespaceWidth); // Check if we've got only whitespace on this line. 416 } 417 if (line.trailingWhitespaceLength && (style.collapseWhitespace || trailingPreWrapWhitespaceNeedsToBeRemoved)) { 418 lastRun.right -= line.trailingWhitespaceWidth; 419 lastRun.end -= line.trailingWhitespaceLength; 423 if (lineState.trailingWhitespaceLength) { 424 // Check if we've got only whitespace on this line. 425 trailingPreWrapWhitespaceNeedsToBeRemoved = !(lineState.committedWidth == lineState.trailingWhitespaceWidth); 426 } 427 } 428 if (lineState.trailingWhitespaceLength && (style.collapseWhitespace || trailingPreWrapWhitespaceNeedsToBeRemoved)) { 429 lastRun.logicalRight -= lineState.trailingWhitespaceWidth; 430 lastRun.end -= lineState.trailingWhitespaceLength; 420 431 if (lastRun.start == lastRun.end) 421 432 lineRuns.removeLast(); 422 line .removeCommittedTrailingWhitespace();433 lineState.removeCommittedTrailingWhitespace(); 423 434 } 424 435 425 436 // If we skipped any whitespace and now the line end is a "preserved" newline, skip the newline too as we are wrapping the line here already. 426 if (originalLineEnd != line.end && style.preserveNewline && line.end < textLength && text[line.end] == '\n') 427 ++line.end; 428 } 429 430 template <typename CharacterType> 431 static void initializeLine(LineState& line, const Style& style, const CharacterType* text, unsigned textLength) 432 { 433 line.committedWidth = 0; 434 line.uncommittedLeft = 0; 435 line.trailingWhitespaceWidth = 0; 436 line.trailingWhitespaceLength = 0; 437 if (lastPosition != lineState.position && style.preserveNewline && lineState.position < textLength && text[lineState.position] == '\n') 438 ++lineState.position; 439 } 440 441 template <typename CharacterType> 442 static void initializeNewLine(LineState& lineState, const Style& style, const CharacterType* text, unsigned textLength, unsigned lineStartRunIndex) 443 { 444 lineState.lineStartRunIndex = lineStartRunIndex; 437 445 // Skip leading whitespace if collapsing whitespace, unless there's an uncommitted fragment pushed from the previous line. 438 446 // FIXME: Be smarter when the run from the previous line does not fit the current line. Right now, we just reprocess it. 439 if (line.uncommittedWidth && !line.fits(line.uncommittedWidth)) 440 line.jumpTo(line.uncommittedStart, 0); // Start over with this fragment. 441 else if (!line.uncommittedWidth) { 447 if (lineState.oveflowedFragment.width) { 448 if (lineState.fits(lineState.oveflowedFragment.width)) 449 lineState.addUncommitted(lineState.oveflowedFragment); 450 else 451 lineState.jumpTo(lineState.oveflowedFragment.start, 0); // Start over with this fragment. 452 } else { 442 453 unsigned spaceCount = 0; 443 line.jumpTo(style.collapseWhitespace ? skipWhitespace(text, line.end, textLength, style.preserveNewline, spaceCount) : line.end, 0); 444 } 454 lineState.jumpTo(style.collapseWhitespace ? skipWhitespace(text, lineState.position, textLength, style.preserveNewline, spaceCount) : lineState.position, 0); 455 } 456 lineState.oveflowedFragment = TextFragment(); 445 457 } 446 458 … … 529 541 530 542 template <typename CharacterType> 531 bool createLineRuns(LineState& line , Layout::RunVector& lineRuns, unsigned& lineCount, LazyLineBreakIterator& lineBreakIterator, const Style& style, const CharacterType* text,543 bool createLineRuns(LineState& lineState, Layout::RunVector& lineRuns, LazyLineBreakIterator& lineBreakIterator, const Style& style, const CharacterType* text, 532 544 unsigned textLength, const RenderText& textRenderer) 533 545 { 534 unsigned previousNumberOfRuns = lineRuns.size();535 TextFragment fragmentForNextLine;536 initializeLine(line, style, text, textLength);537 546 bool lineCanBeWrapped = style.wrapLines || style.breakWordOnOverflow; 538 while (line .end< textLength) {547 while (lineState.position < textLength) { 539 548 // Find the next text fragment. Start from the end of the previous fragment -current line end. 540 TextFragment fragment = nextFragment(line .end, lineBreakIterator, style, text, textLength, line.width(), textRenderer);541 if ((lineCanBeWrapped && !line .fits(fragment.width)) || fragment.mustBreak) {549 TextFragment fragment = nextFragment(lineState.position, lineBreakIterator, style, text, textLength, lineState.width(), textRenderer); 550 if ((lineCanBeWrapped && !lineState.fits(fragment.width)) || fragment.mustBreak) { 542 551 // Overflow wrapping behaviour: 543 552 // 1. Newline character: wraps the line unless it's treated as whitespace. … … 546 555 // 4. First, non-whitespace fragment is either wrapped or kept on the line. (depends on overflow-wrap) 547 556 // 5. Non-whitespace fragment when there's already another fragment on the line gets pushed to the next line. 548 bool isFirstFragment = !line .width();557 bool isFirstFragment = !lineState.width(); 549 558 if (fragment.mustBreak) { 550 559 if (isFirstFragment) 551 line .addUncommitted(fragment);560 lineState.addUncommitted(fragment); 552 561 else { 553 562 // No need to add the new line fragment if there's already content on the line. We are about to close this line anyway. 554 ++line .end;563 ++lineState.position; 555 564 } 556 565 } else if (style.collapseWhitespace && fragment.isWhitespaceOnly) { 557 566 // Whitespace collapse is on: whitespace that doesn't fit is simply skipped. 558 line .end= fragment.end;567 lineState.position = fragment.end; 559 568 } else if (fragment.isWhitespaceOnly || ((isFirstFragment && style.breakWordOnOverflow) || !style.wrapLines)) { // !style.wrapLines: bug138102(preserve existing behavior) 560 // Whitespace collapse is off or non-whitespace content. split the fragment; (modified)fragment -> this line , fragmentForNextLine-> next line.569 // Whitespace collapse is off or non-whitespace content. split the fragment; (modified)fragment -> this lineState, oveflowedFragment -> next line. 561 570 // When this is the only (first) fragment, the first character stays on the line, even if it does not fit. 562 fragmentForNextLine = splitFragmentToFitLine(fragment, line.availableWidth - line.width(), isFirstFragment, textRenderer, text, textLength, style);571 lineState.oveflowedFragment = splitFragmentToFitLine(fragment, lineState.availableWidth - lineState.width(), isFirstFragment, textRenderer, text, textLength, style); 563 572 if (!fragment.isEmpty()) { 564 573 // Whitespace fragments can get pushed entirely to the next line. 565 line .addUncommitted(fragment);574 lineState.addUncommitted(fragment); 566 575 } 567 576 } else if (isFirstFragment) { 568 577 // Non-breakable non-whitespace first fragment. Add it to the current line. -it overflows though. 569 line .addUncommitted(fragment);578 lineState.addUncommitted(fragment); 570 579 } else { 571 580 // Non-breakable non-whitespace fragment when there's already a fragment on the line. Push it to the next line. 572 fragmentForNextLine= fragment;581 lineState.oveflowedFragment = fragment; 573 582 } 574 583 break; … … 577 586 if (fragment.isCollapsedWhitespace) { 578 587 // One trailing whitespace to preserve. 579 line .addUncommittedWhitespace(style.spaceWidth);580 line .commitAndCreateRun(lineRuns);588 lineState.addUncommittedWhitespace(style.spaceWidth); 589 lineState.commitAndCreateRun(lineRuns); 581 590 // And skip the collapsed whitespace. 582 line .jumpTo(fragment.end, line.width() + fragment.width - style.spaceWidth);591 lineState.jumpTo(fragment.end, lineState.width() + fragment.width - style.spaceWidth); 583 592 } else 584 line.addUncommitted(fragment); 585 } 586 line.commitAndCreateRun(lineRuns); 587 // Postprocessing the runs we added for this line. 588 if (previousNumberOfRuns != lineRuns.size()) { 589 removeTrailingWhitespace(line, fragmentForNextLine, lineRuns, style, text, textLength); 590 lineRuns.last().isEndOfLine = true; 591 // Adjust runs' position by taking line's alignment into account. 592 if (float lineLeft = computeLineLeft(style.textAlign, line.availableWidth, line.committedWidth, line.logicalLeftOffset)) { 593 for (unsigned i = previousNumberOfRuns; i < lineRuns.size(); ++i) { 594 lineRuns[i].left += lineLeft; 595 lineRuns[i].right += lineLeft; 596 } 593 lineState.addUncommitted(fragment); 594 } 595 lineState.commitAndCreateRun(lineRuns); 596 return lineState.position >= textLength && lineState.oveflowedFragment.isEmpty(); 597 } 598 599 template <typename CharacterType> 600 static void closeLineEndingAndAdjustRuns(LineState& lineState, Layout::RunVector& lineRuns, unsigned& lineCount, 601 const Style& style, const CharacterType* text, unsigned textLength) 602 { 603 if (lineState.lineStartRunIndex == lineRuns.size()) 604 return; 605 606 ASSERT(lineRuns.size()); 607 removeTrailingWhitespace(lineState, lineRuns, style, text, textLength); 608 // Adjust runs' position by taking line's alignment into account. 609 if (float lineLogicalLeft = computeLineLeft(style.textAlign, lineState.availableWidth, lineState.committedWidth, lineState.logicalLeftOffset)) { 610 for (unsigned i = lineState.lineStartRunIndex; i < lineRuns.size(); ++i) { 611 lineRuns[i].logicalLeft += lineLogicalLeft; 612 lineRuns[i].logicalRight += lineLogicalLeft; 597 613 } 598 ++lineCount;599 }600 if (!fragmentForNextLine.isEmpty())601 line.addUncommitted(fragmentForNextLine);602 return line.end < textLength || line.uncommittedWidth;614 } 615 lineRuns.last().isEndOfLine = true; 616 lineState.committedWidth = 0; 617 lineState.committedLogicalRight = 0; 618 ++lineCount; 603 619 } 604 620 … … 621 637 LayoutUnit lineHeight = lineHeightFromFlow(flow); 622 638 LazyLineBreakIterator lineBreakIterator(textRenderer.text(), flow.style().locale()); 623 LineState line; 639 LineState lineState; 640 bool isEndOfContent = false; 624 641 625 642 do { 626 643 flow.setLogicalHeight(lineHeight * lineCount + borderAndPaddingBefore); 627 updateLineConstrains(flow, line.availableWidth, line.logicalLeftOffset); 628 } while (createLineRuns(line, runs, lineCount, lineBreakIterator, style, text, textLength, textRenderer)); 644 updateLineConstrains(flow, lineState.availableWidth, lineState.logicalLeftOffset); 645 initializeNewLine(lineState, style, text, textLength, runs.size()); 646 isEndOfContent = createLineRuns(lineState, runs, lineBreakIterator, style, text, textLength, textRenderer); 647 closeLineEndingAndAdjustRuns(lineState, runs, lineCount, style, text, textLength); 648 } while (!isEndOfContent); 649 ASSERT(!lineState.uncommittedWidth); 629 650 } 630 651 … … 643 664 644 665 textRenderer.clearNeedsLayout(); 645 646 666 return Layout::create(runs, lineCount); 647 667 } -
trunk/Source/WebCore/rendering/SimpleLineLayout.h
r175259 r175565 44 44 45 45 struct Run { 46 Run() { } 47 Run(unsigned start, float left) 48 : start(start) 49 , end(start) 50 , isEndOfLine(false) 51 , left(left) 52 , right(left) 53 { } 54 Run(unsigned start, unsigned end, float left, float right, bool isEndOfLine) 46 Run(unsigned start, unsigned end, float logicalLeft, float logicalRight, bool isEndOfLine) 55 47 : start(start) 56 48 , end(end) 57 49 , isEndOfLine(isEndOfLine) 58 , l eft(left)59 , right(right)50 , logicalLeft(logicalLeft) 51 , logicalRight(logicalRight) 60 52 { } 61 53 … … 63 55 unsigned end : 31; 64 56 unsigned isEndOfLine : 1; 65 float l eft;66 float right;57 float logicalLeft; 58 float logicalRight; 67 59 }; 68 60 -
trunk/Source/WebCore/rendering/SimpleLineLayoutResolver.h
r174451 r175565 169 169 170 170 float baselinePosition = resolver.m_lineHeight * m_iterator.lineIndex() + resolver.m_baseline; 171 LayoutPoint linePosition(LayoutUnit::fromFloatFloor(run.l eft), roundToInt(baselinePosition - resolver.m_ascent + resolver.m_borderAndPaddingBefore));172 LayoutSize lineSize(LayoutUnit::fromFloatCeil(run. right) - LayoutUnit::fromFloatFloor(run.left), resolver.m_ascent + resolver.m_descent);171 LayoutPoint linePosition(LayoutUnit::fromFloatFloor(run.logicalLeft), roundToInt(baselinePosition - resolver.m_ascent + resolver.m_borderAndPaddingBefore)); 172 LayoutSize lineSize(LayoutUnit::fromFloatCeil(run.logicalRight) - LayoutUnit::fromFloatFloor(run.logicalLeft), resolver.m_ascent + resolver.m_descent); 173 173 return LayoutRect(linePosition, lineSize); 174 174 } … … 180 180 181 181 float baselinePosition = resolver.m_lineHeight * m_iterator.lineIndex() + resolver.m_baseline; 182 return FloatPoint(run.l eft, roundToInt(baselinePosition + resolver.m_borderAndPaddingBefore));182 return FloatPoint(run.logicalLeft, roundToInt(baselinePosition + resolver.m_borderAndPaddingBefore)); 183 183 } 184 184
Note: See TracChangeset
for help on using the changeset viewer.