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

Side by Side Diff: third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h

Issue 1766243003: Improve word-break: break-all and word-wrap: break-word (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@break-all
Patch Set: Remove Mac10.9 from TestExpectations for crbug.com/601166 Created 4 years, 8 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
« no previous file with comments | « third_party/WebKit/LayoutTests/fast/text/break-word-pre-wrap-expected.html ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2000 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All r ight reserved. 3 * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All r ight reserved.
4 * Copyright (C) 2010 Google Inc. All rights reserved. 4 * Copyright (C) 2010 Google Inc. All rights reserved.
5 * Copyright (C) 2013 Adobe Systems Incorporated. 5 * Copyright (C) 2013 Adobe Systems Incorporated.
6 * 6 *
7 * This library is free software; you can redistribute it and/or 7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public 8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either 9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version. 10 * version 2 of the License, or (at your option) any later version.
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 93
94 void increment(); 94 void increment();
95 95
96 void handleBR(EClear&); 96 void handleBR(EClear&);
97 void handleOutOfFlowPositioned(Vector<LineLayoutBox>& positionedObjects); 97 void handleOutOfFlowPositioned(Vector<LineLayoutBox>& positionedObjects);
98 void handleFloat(); 98 void handleFloat();
99 void handleEmptyInline(); 99 void handleEmptyInline();
100 void handleReplaced(); 100 void handleReplaced();
101 bool handleText(WordMeasurements&, bool& hyphenated); 101 bool handleText(WordMeasurements&, bool& hyphenated);
102 void prepareForNextCharacter(const LineLayoutText&, bool& prohibitBreakInsid e, bool previousCharacterIsSpace); 102 void prepareForNextCharacter(const LineLayoutText&, bool& prohibitBreakInsid e, bool previousCharacterIsSpace);
103 bool canBreakAtWhitespace(bool breakWords, WordMeasurement&, bool stoppedIgn oringSpaces, bool& hyphenated, float charWidth, float& hyphenWidth, bool between Words, bool midWordBreak, bool breakAll, bool previousCharacterIsSpace, float la stWidthMeasurement, const LineLayoutText&, const Font&, bool applyWordSpacing, f loat wordSpacing); 103 bool canBreakAtWhitespace(bool breakWords, WordMeasurement&, bool stoppedIgn oringSpaces, bool& hyphenated, float charWidth, float& hyphenWidth, bool between Words, bool midWordBreak, bool canBreakMidWord, bool previousCharacterIsSpace, f loat lastWidthMeasurement, const LineLayoutText&, const Font&, bool applyWordSpa cing, float wordSpacing);
104 bool trailingSpaceExceedsAvailableWidth(bool midWordBreak, const LineLayoutT ext&, WordMeasurement&, bool applyWordSpacing, bool wordSpacing, const Font&); 104 bool trailingSpaceExceedsAvailableWidth(bool canBreakMidWord, const LineLayo utText&, WordMeasurement&, bool applyWordSpacing, bool wordSpacing, const Font&) ;
105 WordMeasurement& calculateWordWidth(WordMeasurements&, LineLayoutText&, unsi gned lastSpace, float& lastWidthMeasurement, float wordSpacingForWordMeasurement , const Font&, float wordTrailingSpaceWidth, UChar); 105 WordMeasurement& calculateWordWidth(WordMeasurements&, LineLayoutText&, unsi gned lastSpace, float& lastWidthMeasurement, float wordSpacingForWordMeasurement , const Font&, float wordTrailingSpaceWidth, UChar);
106 void stopIgnoringSpaces(unsigned& lastSpace); 106 void stopIgnoringSpaces(unsigned& lastSpace);
107 void commitAndUpdateLineBreakIfNeeded(); 107 void commitAndUpdateLineBreakIfNeeded();
108 InlineIterator handleEndOfLine(); 108 InlineIterator handleEndOfLine();
109 109
110 void clearLineBreakIfFitsOnLine() 110 void clearLineBreakIfFitsOnLine()
111 { 111 {
112 if (m_width.fitsOnLine() || m_lastWS == NOWRAP) 112 if (m_width.fitsOnLine() || m_lastWS == NOWRAP)
113 m_lineBreak.clear(); 113 m_lineBreak.clear();
114 } 114 }
115 115
116 private: 116 private:
117 void skipTrailingWhitespace(InlineIterator&, const LineInfo&); 117 void skipTrailingWhitespace(InlineIterator&, const LineInfo&);
118 bool rewindToMidWordBreak(WordMeasurement&, int end, float width);
119 bool rewindToFirstMidWordBreak(LineLayoutText, const ComputedStyle&, const F ont&, bool breakAll, WordMeasurement&);
120 bool rewindToMidWordBreak(LineLayoutText, const ComputedStyle&, const Font&, bool breakAll, WordMeasurement&);
118 121
119 InlineBidiResolver& m_resolver; 122 InlineBidiResolver& m_resolver;
120 123
121 InlineIterator m_current; 124 InlineIterator m_current;
122 InlineIterator m_lineBreak; 125 InlineIterator m_lineBreak;
123 InlineIterator m_startOfIgnoredSpaces; 126 InlineIterator m_startOfIgnoredSpaces;
124 127
125 LineLayoutBlockFlow m_block; 128 LineLayoutBlockFlow m_block;
126 LineLayoutItem m_lastObject; 129 LineLayoutItem m_lastObject;
127 LineLayoutItem m_nextObject; 130 LineLayoutItem m_nextObject;
(...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after
532 { 535 {
533 if ((!from && len == text.textLength()) || text.style()->hasTextCombine()) 536 if ((!from && len == text.textLength()) || text.style()->hasTextCombine())
534 return text.width(from, len, font, LayoutUnit(xPos), text.style()->direc tion(), fallbackFonts, glyphBounds); 537 return text.width(from, len, font, LayoutUnit(xPos), text.style()->direc tion(), fallbackFonts, glyphBounds);
535 538
536 TextRun run = constructTextRun(font, text, from, len, text.styleRef()); 539 TextRun run = constructTextRun(font, text, from, len, text.styleRef());
537 run.setTabSize(!collapseWhiteSpace, text.style()->getTabSize()); 540 run.setTabSize(!collapseWhiteSpace, text.style()->getTabSize());
538 run.setXPos(xPos); 541 run.setXPos(xPos);
539 return font.width(run, fallbackFonts, glyphBounds); 542 return font.width(run, fallbackFonts, glyphBounds);
540 } 543 }
541 544
545 ALWAYS_INLINE int lastBreakablePositionForBreakAll(LineLayoutText text,
546 const ComputedStyle& style, int start, int end)
547 {
548 LazyLineBreakIterator lineBreakIterator(text.text(), style.locale());
549 int lastBreakablePosition = 0, nextBreakablePosition = -1;
550 for (int i = start; ;i = nextBreakablePosition + 1) {
551 lineBreakIterator.isBreakable(i, nextBreakablePosition, LineBreakType::B reakAll);
552 if (nextBreakablePosition == end)
553 return end;
554 if (nextBreakablePosition < 0 || nextBreakablePosition > end)
555 return lastBreakablePosition;
556 lastBreakablePosition = nextBreakablePosition;
557 }
558 }
559
560 ALWAYS_INLINE bool BreakingContext::rewindToMidWordBreak(
561 WordMeasurement& wordMeasurement, int end, float width)
562 {
563 wordMeasurement.endOffset = end;
564 wordMeasurement.width = width;
565
566 m_current.moveTo(m_current.getLineLayoutItem(), end);
567 m_lineBreak.moveTo(m_current.getLineLayoutItem(), m_current.offset());
568 return true;
569 }
570
571 ALWAYS_INLINE bool BreakingContext::rewindToFirstMidWordBreak(LineLayoutText tex t,
572 const ComputedStyle& style, const Font& font, bool breakAll,
573 WordMeasurement& wordMeasurement)
574 {
575 int start = wordMeasurement.startOffset;
576 int end;
577 if (breakAll) {
578 LazyLineBreakIterator lineBreakIterator(text.text(), style.locale());
579 end = -1;
580 lineBreakIterator.isBreakable(start + 1, end, LineBreakType::BreakAll);
581 if (end < 0)
582 return false;
583 } else {
584 end = start + 1;
585 }
586 if (end >= wordMeasurement.endOffset)
587 return false;
588
589 float width = textWidth(text, start, end - start, font, m_width.currentWidth (), m_collapseWhiteSpace);
590 return rewindToMidWordBreak(wordMeasurement, end, width);
591 }
592
593 ALWAYS_INLINE bool BreakingContext::rewindToMidWordBreak(LineLayoutText text,
594 const ComputedStyle& style, const Font& font, bool breakAll,
595 WordMeasurement& wordMeasurement)
596 {
597 int start = wordMeasurement.startOffset;
598 int len = wordMeasurement.endOffset - start;
599 if (!len)
600 return false;
601 if (m_width.availableWidth() <= LayoutUnit::epsilon())
602 return rewindToFirstMidWordBreak(text, style, font, breakAll, wordMeasur ement);
603
604 TextRun run = constructTextRun(font, text, start, len, style);
605 run.setTabSize(!m_collapseWhiteSpace, style.getTabSize());
606 run.setXPos(m_width.currentWidth());
607
608 // TODO(kojii): should be replaced with safe-to-break when hb is ready.
609 float x = m_width.availableWidth() + LayoutUnit::epsilon() - m_width.current Width();
610 len = font.offsetForPosition(run, x, false);
611 if (!len && !m_width.currentWidth())
612 return rewindToFirstMidWordBreak(text, style, font, breakAll, wordMeasur ement);
613
614 FloatRect rect = font.selectionRectForText(run, FloatPoint(), 0, 0, len);
615 // HarfBuzzShaper ignores includePartialGlyphs=false, so we need to find the
616 // real width that fits. Usually a few loops at maximum.
617 if (len && !m_width.fitsOnLine(rect.width())) {
618 for (; ; ) {
619 --len;
620 if (!len) {
621 rect.setWidth(0);
622 break;
623 }
624 rect = font.selectionRectForText(run, FloatPoint(), 0, 0, len);
625 if (m_width.fitsOnLine(rect.width()))
626 break;
627 }
628 }
629
630 int end = start + len;
631 if (breakAll) {
632 end = lastBreakablePositionForBreakAll(text, style, start, end);
633 if (!end)
634 return false;
635 rect = font.selectionRectForText(run, FloatPoint(), 0, 0, end - start);
636 }
637
638 return rewindToMidWordBreak(wordMeasurement, end, rect.width());
639 }
640
542 inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool & hyphenated) 641 inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool & hyphenated)
543 { 642 {
544 if (!m_current.offset()) 643 if (!m_current.offset())
545 m_appliedStartWidth = false; 644 m_appliedStartWidth = false;
546 645
547 LineLayoutText layoutText(m_current.getLineLayoutItem()); 646 LineLayoutText layoutText(m_current.getLineLayoutItem());
548 647
549 // If we have left a no-wrap inline and entered an autowrap inline while ign oring spaces 648 // If we have left a no-wrap inline and entered an autowrap inline while ign oring spaces
550 // then we need to mark the start of the autowrap inline as a potential line break now. 649 // then we need to mark the start of the autowrap inline as a potential line break now.
551 if (m_autoWrap && !ComputedStyle::autoWrap(m_lastWS) && m_ignoringSpaces) { 650 if (m_autoWrap && !ComputedStyle::autoWrap(m_lastWS) && m_ignoringSpaces) {
552 m_width.commit(); 651 m_width.commit();
553 m_lineBreak.moveToStartOf(m_current.getLineLayoutItem()); 652 m_lineBreak.moveToStartOf(m_current.getLineLayoutItem());
554 } 653 }
555 654
556 const ComputedStyle& style = layoutText.styleRef(m_lineInfo.isFirstLine()); 655 const ComputedStyle& style = layoutText.styleRef(m_lineInfo.isFirstLine());
557 const Font& font = style.font(); 656 const Font& font = style.font();
558 657
559 unsigned lastSpace = m_current.offset(); 658 unsigned lastSpace = m_current.offset();
560 float wordSpacing = m_currentStyle->wordSpacing(); 659 float wordSpacing = m_currentStyle->wordSpacing();
561 float lastSpaceWordSpacing = 0; 660 float lastSpaceWordSpacing = 0;
562 float wordSpacingForWordMeasurement = 0; 661 float wordSpacingForWordMeasurement = 0;
563 662
564 float widthFromLastBreakingOpportunity = m_width.uncommittedWidth();
565 float charWidth = 0; 663 float charWidth = 0;
566 // Auto-wrapping text should wrap in the middle of a word only if it could n ot wrap before the word, 664 // Auto-wrapping text should wrap in the middle of a word only if it could n ot wrap before the word,
567 // which is only possible if the word is the first thing on the line, that i s, if |w| is zero. 665 // which is only possible if the word is the first thing on the line, that i s, if |w| is zero.
568 bool breakWords = m_currentStyle->breakWords() && ((m_autoWrap && !m_width.c ommittedWidth()) || m_currWS == PRE); 666 bool breakWords = m_currentStyle->breakWords() && ((m_autoWrap && !m_width.c ommittedWidth()) || m_currWS == PRE);
569 bool midWordBreak = false;
570 bool breakAll = m_currentStyle->wordBreak() == BreakAllWordBreak && m_autoWr ap; 667 bool breakAll = m_currentStyle->wordBreak() == BreakAllWordBreak && m_autoWr ap;
571 bool keepAll = m_currentStyle->wordBreak() == KeepAllWordBreak && m_autoWrap ; 668 bool keepAll = m_currentStyle->wordBreak() == KeepAllWordBreak && m_autoWrap ;
572 bool prohibitBreakInside = m_currentStyle->hasTextCombine() && layoutText.is CombineText() && LineLayoutTextCombine(layoutText).isCombined(); 669 bool prohibitBreakInside = m_currentStyle->hasTextCombine() && layoutText.is CombineText() && LineLayoutTextCombine(layoutText).isCombined();
573 670
574 // This is currently only used for word-break: break-all, specifically for t he case 671 // This is currently only used for word-break: break-all, specifically for t he case
575 // where we have a break opportunity within a word, then a string of non-bre akable 672 // where we have a break opportunity within a word, then a string of non-bre akable
576 // content that ends up making our word wider than the current line. 673 // content that ends up making our word wider than the current line.
577 // See: fast/css3-text/css3-word-break/word-break-all-wrap-with-floats.html 674 // See: fast/css3-text/css3-word-break/word-break-all-wrap-with-floats.html
578 float widthMeasurementAtLastBreakOpportunity = 0; 675 float widthMeasurementAtLastBreakOpportunity = 0;
579 676
580 float hyphenWidth = 0; 677 float hyphenWidth = 0;
581 678
582 if (layoutText.isSVGInlineText()) { 679 if (layoutText.isSVGInlineText()) {
583 breakWords = false; 680 breakWords = false;
584 breakAll = false; 681 breakAll = false;
585 keepAll = false; 682 keepAll = false;
586 } 683 }
587 684
685 // Use LineBreakType::Normal for break-all. When a word does not fit,
686 // rewindToMidWordBreak() finds the mid-word break point.
687 LineBreakType lineBreakType = keepAll ? LineBreakType::KeepAll : LineBreakTy pe::Normal;
688 bool canBreakMidWord = breakAll || breakWords;
689
588 if (layoutText.isWordBreak()) { 690 if (layoutText.isWordBreak()) {
589 m_width.commit(); 691 m_width.commit();
590 m_lineBreak.moveToStartOf(m_current.getLineLayoutItem()); 692 m_lineBreak.moveToStartOf(m_current.getLineLayoutItem());
591 ASSERT(m_current.offset() == layoutText.textLength()); 693 ASSERT(m_current.offset() == layoutText.textLength());
592 } 694 }
593 695
594 if (m_layoutTextInfo.m_text != layoutText) { 696 if (m_layoutTextInfo.m_text != layoutText) {
595 m_layoutTextInfo.m_text = layoutText; 697 m_layoutTextInfo.m_text = layoutText;
596 m_layoutTextInfo.m_font = &font; 698 m_layoutTextInfo.m_font = &font;
597 m_layoutTextInfo.m_lineBreakIterator.resetStringAndReleaseIterator(layou tText.text(), style.locale()); 699 m_layoutTextInfo.m_lineBreakIterator.resetStringAndReleaseIterator(layou tText.text(), style.locale());
(...skipping 19 matching lines...) Expand all
617 m_width.setTrailingWhitespaceWidth(0); 719 m_width.setTrailingWhitespaceWidth(0);
618 } 720 }
619 721
620 if (c == softHyphenCharacter && m_autoWrap && !hyphenWidth) { 722 if (c == softHyphenCharacter && m_autoWrap && !hyphenWidth) {
621 hyphenWidth = layoutText.hyphenWidth(font, textDirectionFromUnicode( m_resolver.position().direction())); 723 hyphenWidth = layoutText.hyphenWidth(font, textDirectionFromUnicode( m_resolver.position().direction()));
622 m_width.addUncommittedWidth(hyphenWidth); 724 m_width.addUncommittedWidth(hyphenWidth);
623 } 725 }
624 726
625 bool applyWordSpacing = false; 727 bool applyWordSpacing = false;
626 728
627 // Determine if we should try breaking in the middle of a word.
628 if (breakWords && !midWordBreak && !U16_IS_TRAIL(c)) {
629 widthFromLastBreakingOpportunity += charWidth;
630 bool midWordBreakIsBeforeSurrogatePair = U16_IS_LEAD(c) && m_current .offset() + 1 < layoutText.textLength() && U16_IS_TRAIL(layoutText.uncheckedChar acterAt(m_current.offset() + 1));
631 charWidth = textWidth(layoutText, m_current.offset(), midWordBreakIs BeforeSurrogatePair ? 2 : 1, font, m_width.committedWidth() + widthFromLastBreak ingOpportunity, m_collapseWhiteSpace);
632 midWordBreak = m_width.committedWidth() + widthFromLastBreakingOppor tunity + charWidth > m_width.availableWidth();
633 }
634
635 // Determine if we are in the whitespace between words. 729 // Determine if we are in the whitespace between words.
636 int nextBreakablePosition = m_current.nextBreakablePosition(); 730 int nextBreakablePosition = m_current.nextBreakablePosition();
637 bool betweenWords = c == newlineCharacter || (m_currWS != PRE && !m_atSt art && m_layoutTextInfo.m_lineBreakIterator.isBreakable(m_current.offset(), next BreakablePosition, breakAll ? LineBreakType::BreakAll : keepAll ? LineBreakType: :KeepAll : LineBreakType::Normal)); 731 bool betweenWords = c == newlineCharacter || (m_currWS != PRE && !m_atSt art && m_layoutTextInfo.m_lineBreakIterator.isBreakable(m_current.offset(), next BreakablePosition, lineBreakType));
638 m_current.setNextBreakablePosition(nextBreakablePosition); 732 m_current.setNextBreakablePosition(nextBreakablePosition);
639 733
640 // If we're in the middle of a word or at the start of a new one and can 't break there, then continue to the next character. 734 // If we're in the middle of a word or at the start of a new one and can 't break there, then continue to the next character.
641 if (!betweenWords && !midWordBreak) { 735 if (!betweenWords) {
642 if (m_ignoringSpaces) { 736 if (m_ignoringSpaces) {
643 // Stop ignoring spaces and begin at this 737 // Stop ignoring spaces and begin at this
644 // new point. 738 // new point.
645 lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0; 739 lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
646 wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasure ments.last().width) ? wordSpacing : 0; 740 wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasure ments.last().width) ? wordSpacing : 0;
647 stopIgnoringSpaces(lastSpace); 741 stopIgnoringSpaces(lastSpace);
648 } 742 }
649 743
650 prepareForNextCharacter(layoutText, prohibitBreakInside, previousCha racterIsSpace); 744 prepareForNextCharacter(layoutText, prohibitBreakInside, previousCha racterIsSpace);
651 m_atStart = false; 745 m_atStart = false;
(...skipping 17 matching lines...) Expand all
669 lastSpaceWordSpacing = 0; 763 lastSpaceWordSpacing = 0;
670 wordSpacingForWordMeasurement = 0; 764 wordSpacingForWordMeasurement = 0;
671 stoppedIgnoringSpaces = true; 765 stoppedIgnoringSpaces = true;
672 stopIgnoringSpaces(lastSpace); 766 stopIgnoringSpaces(lastSpace);
673 } 767 }
674 768
675 // Update our tally of the width since the last breakable position with the width of the word we're now at the end of. 769 // Update our tally of the width since the last breakable position with the width of the word we're now at the end of.
676 float lastWidthMeasurement; 770 float lastWidthMeasurement;
677 WordMeasurement& wordMeasurement = calculateWordWidth(wordMeasurements, layoutText, lastSpace, lastWidthMeasurement, wordSpacingForWordMeasurement, font , wordTrailingSpaceWidth, c); 771 WordMeasurement& wordMeasurement = calculateWordWidth(wordMeasurements, layoutText, lastSpace, lastWidthMeasurement, wordSpacingForWordMeasurement, font , wordTrailingSpaceWidth, c);
678 lastWidthMeasurement += lastSpaceWordSpacing; 772 lastWidthMeasurement += lastSpaceWordSpacing;
773
774 bool midWordBreak = false;
775 if (canBreakMidWord && !m_width.fitsOnLine(lastWidthMeasurement)
776 && rewindToMidWordBreak(layoutText, style, font, breakAll, wordMeasu rement)) {
777 lastWidthMeasurement = wordMeasurement.width;
778 midWordBreak = true;
779 }
780
679 m_width.addUncommittedWidth(lastWidthMeasurement); 781 m_width.addUncommittedWidth(lastWidthMeasurement);
680 782
681 // We keep track of the total width contributed by trailing space as we often want to exclude it when determining 783 // We keep track of the total width contributed by trailing space as we often want to exclude it when determining
682 // if a run fits on a line. 784 // if a run fits on a line.
683 if (m_collapseWhiteSpace && previousCharacterIsSpace && m_currentCharact erIsSpace && lastWidthMeasurement) 785 if (m_collapseWhiteSpace && previousCharacterIsSpace && m_currentCharact erIsSpace && lastWidthMeasurement)
684 m_width.setTrailingWhitespaceWidth(lastWidthMeasurement); 786 m_width.setTrailingWhitespaceWidth(lastWidthMeasurement);
685 787
686 // If this is the end of the first word in run of text then make sure we apply the width from any leading inlines. 788 // If this is the end of the first word in run of text then make sure we apply the width from any leading inlines.
687 // For example: '<span style="margin-left: 5px;"><span style="margin-lef t: 10px;">FirstWord</span></span>' would 789 // For example: '<span style="margin-left: 5px;"><span style="margin-lef t: 10px;">FirstWord</span></span>' would
688 // apply a width of 15px from the two span ancestors. 790 // apply a width of 15px from the two span ancestors.
689 if (!m_appliedStartWidth) { 791 if (!m_appliedStartWidth) {
690 m_width.addUncommittedWidth(inlineLogicalWidthFromAncestorsIfNeeded( m_current.getLineLayoutItem(), true, false).toFloat()); 792 m_width.addUncommittedWidth(inlineLogicalWidthFromAncestorsIfNeeded( m_current.getLineLayoutItem(), true, false).toFloat());
691 m_appliedStartWidth = true; 793 m_appliedStartWidth = true;
692 } 794 }
693 795
694 applyWordSpacing = wordSpacing && m_currentCharacterIsSpace;
695
696 // If we haven't hit a breakable position yet and already don't fit on t he line try to move below any floats. 796 // If we haven't hit a breakable position yet and already don't fit on t he line try to move below any floats.
697 if (!m_width.committedWidth() && m_autoWrap && !m_width.fitsOnLine() && !widthMeasurementAtLastBreakOpportunity) 797 if (!m_width.committedWidth() && m_autoWrap && !m_width.fitsOnLine() && !widthMeasurementAtLastBreakOpportunity)
698 m_width.fitBelowFloats(m_lineInfo.isFirstLine()); 798 m_width.fitBelowFloats(m_lineInfo.isFirstLine());
699 799
700 // If there is a soft-break available at this whitespace position then t ake it. 800 // If there is a soft-break available at this whitespace position then t ake it.
701 applyWordSpacing = wordSpacing && m_currentCharacterIsSpace; 801 applyWordSpacing = wordSpacing && m_currentCharacterIsSpace;
702 if (canBreakAtWhitespace(breakWords, wordMeasurement, stoppedIgnoringSpa ces, hyphenated, charWidth, hyphenWidth, betweenWords, midWordBreak, breakAll, p reviousCharacterIsSpace, lastWidthMeasurement, layoutText, font, applyWordSpacin g, wordSpacing)) 802 if (canBreakAtWhitespace(breakWords, wordMeasurement, stoppedIgnoringSpa ces, hyphenated, charWidth, hyphenWidth, betweenWords, midWordBreak, canBreakMid Word, previousCharacterIsSpace, lastWidthMeasurement, layoutText, font, applyWor dSpacing, wordSpacing))
703 return false; 803 return false;
704 804
705 // If there is a hard-break available at this whitespace position then t ake it. 805 // If there is a hard-break available at this whitespace position then t ake it.
706 if (c == newlineCharacter && m_preservesNewline) { 806 if (c == newlineCharacter && m_preservesNewline) {
707 if (!stoppedIgnoringSpaces && m_current.offset()) 807 if (!stoppedIgnoringSpaces && m_current.offset())
708 m_lineMidpointState.ensureCharacterGetsLineBox(m_current); 808 m_lineMidpointState.ensureCharacterGetsLineBox(m_current);
709 m_lineBreak.moveTo(m_current.getLineLayoutItem(), m_current.offset() , m_current.nextBreakablePosition()); 809 m_lineBreak.moveTo(m_current.getLineLayoutItem(), m_current.offset() , m_current.nextBreakablePosition());
710 m_lineBreak.increment(); 810 m_lineBreak.increment();
711 m_lineInfo.setPreviousLineBrokeCleanly(true); 811 m_lineInfo.setPreviousLineBrokeCleanly(true);
712 return true; 812 return true;
713 } 813 }
714 814
715 // Auto-wrapping text should not wrap in the middle of a word once it ha s had an 815 // Auto-wrapping text should not wrap in the middle of a word once it ha s had an
716 // opportunity to break after a word. 816 // opportunity to break after a word.
717 if (m_autoWrap && betweenWords) { 817 if (m_autoWrap && betweenWords) {
718 m_width.commit(); 818 m_width.commit();
719 widthFromLastBreakingOpportunity = 0;
720 m_lineBreak.moveTo(m_current.getLineLayoutItem(), m_current.offset() , m_current.nextBreakablePosition()); 819 m_lineBreak.moveTo(m_current.getLineLayoutItem(), m_current.offset() , m_current.nextBreakablePosition());
721 breakWords = false; 820 breakWords = false;
821 canBreakMidWord = breakAll;
722 widthMeasurementAtLastBreakOpportunity = lastWidthMeasurement; 822 widthMeasurementAtLastBreakOpportunity = lastWidthMeasurement;
723 } 823 }
724 824
725 // Remember this as a breakable position in case adding the end width fo rces a break.
726 if (midWordBreak && !U16_IS_TRAIL(c) && !(WTF::Unicode::category(c) & (W TF::Unicode::Mark_NonSpacing | WTF::Unicode::Mark_Enclosing | WTF::Unicode::Mark _SpacingCombining))) {
727 m_lineBreak.moveTo(m_current.getLineLayoutItem(), m_current.offset() , m_current.nextBreakablePosition());
728 midWordBreak &= (breakWords || breakAll);
729 }
730
731 if (betweenWords) { 825 if (betweenWords) {
732 lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0; 826 lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
733 wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurement .width) ? wordSpacing : 0; 827 wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurement .width) ? wordSpacing : 0;
734 lastSpace = !breakAll || m_currentCharacterIsSpace ? m_current.offse t() : lastSpace; 828 lastSpace = m_current.offset();
735 } 829 }
736 830
737 // If we encounter a newline, or if we encounter a second space, we need to go ahead and break up 831 // If we encounter a newline, or if we encounter a second space, we need to go ahead and break up
738 // this run and enter a mode where we start collapsing spaces. 832 // this run and enter a mode where we start collapsing spaces.
739 if (!m_ignoringSpaces && m_currentStyle->collapseWhiteSpace()) { 833 if (!m_ignoringSpaces && m_currentStyle->collapseWhiteSpace()) {
740 if (m_currentCharacterIsSpace && previousCharacterIsSpace) { 834 if (m_currentCharacterIsSpace && previousCharacterIsSpace) {
741 m_ignoringSpaces = true; 835 m_ignoringSpaces = true;
742 836
743 // We just entered a mode where we are ignoring spaces. Create a midpoint to terminate the run 837 // We just entered a mode where we are ignoring spaces. Create a midpoint to terminate the run
744 // before the second space. 838 // before the second space.
(...skipping 10 matching lines...) Expand all
755 m_layoutTextInfo.m_lineBreakIterator.setPriorContext(lastCharacter, secondTo LastCharacter); 849 m_layoutTextInfo.m_lineBreakIterator.setPriorContext(lastCharacter, secondTo LastCharacter);
756 850
757 wordMeasurements.grow(wordMeasurements.size() + 1); 851 wordMeasurements.grow(wordMeasurements.size() + 1);
758 WordMeasurement& wordMeasurement = wordMeasurements.last(); 852 WordMeasurement& wordMeasurement = wordMeasurements.last();
759 wordMeasurement.layoutText = layoutText; 853 wordMeasurement.layoutText = layoutText;
760 854
761 // IMPORTANT: current.offset() is > layoutText.textLength() here! 855 // IMPORTANT: current.offset() is > layoutText.textLength() here!
762 float lastWidthMeasurement = 0; 856 float lastWidthMeasurement = 0;
763 wordMeasurement.startOffset = lastSpace; 857 wordMeasurement.startOffset = lastSpace;
764 wordMeasurement.endOffset = m_current.offset(); 858 wordMeasurement.endOffset = m_current.offset();
859 bool midWordBreak = false;
765 if (!m_ignoringSpaces) { 860 if (!m_ignoringSpaces) {
766 lastWidthMeasurement = textWidth(layoutText, lastSpace, m_current.offset () - lastSpace, font, m_width.currentWidth(), m_collapseWhiteSpace, &wordMeasure ment.fallbackFonts, &wordMeasurement.glyphBounds); 861 lastWidthMeasurement = textWidth(layoutText, lastSpace, m_current.offset () - lastSpace, font, m_width.currentWidth(), m_collapseWhiteSpace, &wordMeasure ment.fallbackFonts, &wordMeasurement.glyphBounds);
767 wordMeasurement.width = lastWidthMeasurement + wordSpacingForWordMeasure ment; 862 wordMeasurement.width = lastWidthMeasurement + wordSpacingForWordMeasure ment;
768 wordMeasurement.glyphBounds.move(wordSpacingForWordMeasurement, 0); 863 wordMeasurement.glyphBounds.move(wordSpacingForWordMeasurement, 0);
864
865 if (canBreakMidWord && !m_width.fitsOnLine(lastWidthMeasurement)
866 && rewindToMidWordBreak(layoutText, style, font, breakAll, wordMeasu rement)) {
867 lastWidthMeasurement = wordMeasurement.width;
868 midWordBreak = true;
869 }
769 } 870 }
770 lastWidthMeasurement += lastSpaceWordSpacing; 871 lastWidthMeasurement += lastSpaceWordSpacing;
771 872
772 LayoutUnit additionalWidthFromAncestors = inlineLogicalWidthFromAncestorsIfN eeded(m_current.getLineLayoutItem(), !m_appliedStartWidth, m_includeEndWidth); 873 LayoutUnit additionalWidthFromAncestors = inlineLogicalWidthFromAncestorsIfN eeded(m_current.getLineLayoutItem(), !m_appliedStartWidth, m_includeEndWidth);
773 m_width.addUncommittedWidth(lastWidthMeasurement + additionalWidthFromAncest ors); 874 m_width.addUncommittedWidth(lastWidthMeasurement + additionalWidthFromAncest ors);
774 875
775 if (m_collapseWhiteSpace && m_currentCharacterIsSpace && lastWidthMeasuremen t) 876 if (m_collapseWhiteSpace && m_currentCharacterIsSpace && lastWidthMeasuremen t)
776 m_width.setTrailingWhitespaceWidth(lastWidthMeasurement + additionalWidt hFromAncestors); 877 m_width.setTrailingWhitespaceWidth(lastWidthMeasurement + additionalWidt hFromAncestors);
777 878
778 m_includeEndWidth = false; 879 m_includeEndWidth = false;
779 880
780 if (!m_width.fitsOnLine()) { 881 if (midWordBreak) {
781 if (breakAll && widthMeasurementAtLastBreakOpportunity) { 882 m_width.commit();
782 m_width.addUncommittedWidth(widthMeasurementAtLastBreakOpportunity); 883 m_atEnd = true;
783 m_width.commit(); 884 } else if (!m_width.fitsOnLine() && !hyphenated
784 return true; 885 && m_lineBreak.previousInSameNode() == softHyphenCharacter) {
785 } 886 hyphenated = true;
786 if (!hyphenated && m_lineBreak.previousInSameNode() == softHyphenCharact er) { 887 m_atEnd = true;
787 hyphenated = true;
788 m_atEnd = true;
789 }
790 } 888 }
791 return false; 889 return false;
792 } 890 }
793 891
794 inline void BreakingContext::prepareForNextCharacter(const LineLayoutText& layou tText, bool& prohibitBreakInside, bool previousCharacterIsSpace) 892 inline void BreakingContext::prepareForNextCharacter(const LineLayoutText& layou tText, bool& prohibitBreakInside, bool previousCharacterIsSpace)
795 { 893 {
796 if (layoutText.isSVGInlineText() && m_current.offset()) { 894 if (layoutText.isSVGInlineText() && m_current.offset()) {
797 // Force creation of new InlineBoxes for each absolute positioned charac ter (those that start new text chunks). 895 // Force creation of new InlineBoxes for each absolute positioned charac ter (those that start new text chunks).
798 if (LineLayoutSVGInlineText(layoutText).characterStartsNewTextChunk(m_cu rrent.offset())) 896 if (LineLayoutSVGInlineText(layoutText).characterStartsNewTextChunk(m_cu rrent.offset()))
799 m_lineMidpointState.ensureCharacterGetsLineBox(m_current); 897 m_lineMidpointState.ensureCharacterGetsLineBox(m_current);
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
835 if (wordTrailingSpaceWidth && c == spaceCharacter) 933 if (wordTrailingSpaceWidth && c == spaceCharacter)
836 lastWidthMeasurement = textWidth(layoutText, lastSpace, m_current.offset () + 1 - lastSpace, font, m_width.currentWidth(), m_collapseWhiteSpace, &wordMea surement.fallbackFonts, &wordMeasurement.glyphBounds) - wordTrailingSpaceWidth; 934 lastWidthMeasurement = textWidth(layoutText, lastSpace, m_current.offset () + 1 - lastSpace, font, m_width.currentWidth(), m_collapseWhiteSpace, &wordMea surement.fallbackFonts, &wordMeasurement.glyphBounds) - wordTrailingSpaceWidth;
837 else 935 else
838 lastWidthMeasurement = textWidth(layoutText, lastSpace, m_current.offset () - lastSpace, font, m_width.currentWidth(), m_collapseWhiteSpace, &wordMeasure ment.fallbackFonts, &wordMeasurement.glyphBounds); 936 lastWidthMeasurement = textWidth(layoutText, lastSpace, m_current.offset () - lastSpace, font, m_width.currentWidth(), m_collapseWhiteSpace, &wordMeasure ment.fallbackFonts, &wordMeasurement.glyphBounds);
839 937
840 wordMeasurement.width = lastWidthMeasurement + wordSpacingForWordMeasurement ; 938 wordMeasurement.width = lastWidthMeasurement + wordSpacingForWordMeasurement ;
841 wordMeasurement.glyphBounds.move(wordSpacingForWordMeasurement, 0); 939 wordMeasurement.glyphBounds.move(wordSpacingForWordMeasurement, 0);
842 return wordMeasurement; 940 return wordMeasurement;
843 } 941 }
844 942
845 inline bool BreakingContext::trailingSpaceExceedsAvailableWidth(bool midWordBrea k, const LineLayoutText& layoutText, WordMeasurement& wordMeasurement, bool appl yWordSpacing, bool wordSpacing, const Font& font) 943 inline bool BreakingContext::trailingSpaceExceedsAvailableWidth(bool canBreakMid Word, const LineLayoutText& layoutText, WordMeasurement& wordMeasurement, bool a pplyWordSpacing, bool wordSpacing, const Font& font)
846 { 944 {
847 // If we break only after white-space, consider the current character 945 // If we break only after white-space, consider the current character
848 // as candidate width for this line. 946 // as candidate width for this line.
849 if (m_width.fitsOnLine() && m_currentCharacterIsSpace && m_currentStyle->bre akOnlyAfterWhiteSpace() && !midWordBreak) { 947 if (m_width.fitsOnLine() && m_currentCharacterIsSpace && m_currentStyle->bre akOnlyAfterWhiteSpace() && !canBreakMidWord) {
850 float charWidth = textWidth(layoutText, m_current.offset(), 1, font, m_w idth.currentWidth(), m_collapseWhiteSpace, &wordMeasurement.fallbackFonts, &word Measurement.glyphBounds) + (applyWordSpacing ? wordSpacing : 0); 948 float charWidth = textWidth(layoutText, m_current.offset(), 1, font, m_w idth.currentWidth(), m_collapseWhiteSpace, &wordMeasurement.fallbackFonts, &word Measurement.glyphBounds) + (applyWordSpacing ? wordSpacing : 0);
851 // Check if line is too big even without the extra space 949 // Check if line is too big even without the extra space
852 // at the end of the line. If it is not, do nothing. 950 // at the end of the line. If it is not, do nothing.
853 // If the line needs the extra whitespace to be too long, 951 // If the line needs the extra whitespace to be too long,
854 // then move the line break to the space and skip all 952 // then move the line break to the space and skip all
855 // additional whitespace. 953 // additional whitespace.
856 if (!m_width.fitsOnLine(charWidth)) { 954 if (!m_width.fitsOnLine(charWidth)) {
857 m_lineBreak.moveTo(m_current.getLineLayoutItem(), m_current.offset() , m_current.nextBreakablePosition()); 955 m_lineBreak.moveTo(m_current.getLineLayoutItem(), m_current.offset() , m_current.nextBreakablePosition());
858 skipTrailingWhitespace(m_lineBreak, m_lineInfo); 956 skipTrailingWhitespace(m_lineBreak, m_lineInfo);
859 return true; 957 return true;
860 } 958 }
861 } 959 }
862 return false; 960 return false;
863 } 961 }
864 962
865 inline bool BreakingContext::canBreakAtWhitespace(bool breakWords, WordMeasureme nt& wordMeasurement, bool stoppedIgnoringSpaces, bool& hyphenated, float charWid th, float& hyphenWidth, bool betweenWords, bool midWordBreak, bool breakAll, boo l previousCharacterIsSpace, float lastWidthMeasurement, const LineLayoutText& la youtText, const Font& font, bool applyWordSpacing, float wordSpacing) 963 inline bool BreakingContext::canBreakAtWhitespace(bool breakWords, WordMeasureme nt& wordMeasurement, bool stoppedIgnoringSpaces, bool& hyphenated, float charWid th, float& hyphenWidth, bool betweenWords, bool midWordBreak, bool canBreakMidWo rd, bool previousCharacterIsSpace, float lastWidthMeasurement, const LineLayoutT ext& layoutText, const Font& font, bool applyWordSpacing, float wordSpacing)
866 { 964 {
867 if (!m_autoWrap && !breakWords) 965 if (!m_autoWrap && !breakWords)
868 return false; 966 return false;
869 967
870 // If we break only after white-space, consider the current character 968 // If we break only after white-space, consider the current character
871 // as candidate width for this line. 969 // as candidate width for this line.
872 if (trailingSpaceExceedsAvailableWidth(midWordBreak, layoutText, wordMeasure ment, applyWordSpacing, wordSpacing, font) || !m_width.fitsOnLine()) { 970 if (midWordBreak
971 || trailingSpaceExceedsAvailableWidth(canBreakMidWord, layoutText, wordM easurement, applyWordSpacing, wordSpacing, font)
972 || !m_width.fitsOnLine()) {
873 if (m_lineBreak.atTextParagraphSeparator()) { 973 if (m_lineBreak.atTextParagraphSeparator()) {
874 if (!stoppedIgnoringSpaces && m_current.offset() > 0) 974 if (!stoppedIgnoringSpaces && m_current.offset() > 0)
875 m_lineMidpointState.ensureCharacterGetsLineBox(m_current); 975 m_lineMidpointState.ensureCharacterGetsLineBox(m_current);
876 m_lineBreak.increment(); 976 m_lineBreak.increment();
877 m_lineInfo.setPreviousLineBrokeCleanly(true); 977 m_lineInfo.setPreviousLineBrokeCleanly(true);
878 wordMeasurement.endOffset = m_lineBreak.offset(); 978 wordMeasurement.endOffset = m_lineBreak.offset();
879 } 979 }
880 if (m_lineBreak.getLineLayoutItem() && m_lineBreak.offset() && m_lineBre ak.getLineLayoutItem().isText() && LineLayoutText(m_lineBreak.getLineLayoutItem( )).textLength() && LineLayoutText(m_lineBreak.getLineLayoutItem()).characterAt(m _lineBreak.offset() - 1) == softHyphenCharacter) 980 if (m_lineBreak.getLineLayoutItem() && m_lineBreak.offset() && m_lineBre ak.getLineLayoutItem().isText() && LineLayoutText(m_lineBreak.getLineLayoutItem( )).textLength() && LineLayoutText(m_lineBreak.getLineLayoutItem()).characterAt(m _lineBreak.offset() - 1) == softHyphenCharacter)
881 hyphenated = true; 981 hyphenated = true;
882 if (m_lineBreak.offset() && m_lineBreak.offset() != (unsigned)wordMeasur ement.endOffset && !wordMeasurement.width) { 982 if (m_lineBreak.offset() && m_lineBreak.offset() != (unsigned)wordMeasur ement.endOffset && !wordMeasurement.width) {
883 if (charWidth) { 983 if (charWidth) {
884 wordMeasurement.endOffset = m_lineBreak.offset(); 984 wordMeasurement.endOffset = m_lineBreak.offset();
885 wordMeasurement.width = charWidth; 985 wordMeasurement.width = charWidth;
886 } 986 }
887 } 987 }
888 // Didn't fit. Jump to the end unless there's still an opportunity to co llapse whitespace. 988 // Didn't fit. Jump to the end unless there's still an opportunity to co llapse whitespace.
889 if (m_ignoringSpaces || !m_collapseWhiteSpace || !m_currentCharacterIsSp ace || !previousCharacterIsSpace) { 989 if (m_ignoringSpaces || !m_collapseWhiteSpace || !m_currentCharacterIsSp ace || !previousCharacterIsSpace) {
890 m_atEnd = true; 990 m_atEnd = true;
891 return true; 991 return true;
892 } 992 }
893 } else { 993 } else {
894 if (!betweenWords || (midWordBreak && !m_autoWrap) || (breakAll && !m_cu rrentCharacterIsSpace)) 994 if (!betweenWords || (midWordBreak && !m_autoWrap))
895 m_width.addUncommittedWidth(-lastWidthMeasurement); 995 m_width.addUncommittedWidth(-lastWidthMeasurement);
896 if (hyphenWidth) { 996 if (hyphenWidth) {
897 // Subtract the width of the soft hyphen out since we fit on a line. 997 // Subtract the width of the soft hyphen out since we fit on a line.
898 m_width.addUncommittedWidth(-hyphenWidth); 998 m_width.addUncommittedWidth(-hyphenWidth);
899 hyphenWidth = 0; 999 hyphenWidth = 0;
900 } 1000 }
901 } 1001 }
902 return false; 1002 return false;
903 } 1003 }
904 1004
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
981 1081
982 if (style.getTextIndentType() == TextIndentHanging) 1082 if (style.getTextIndentType() == TextIndentHanging)
983 indentText = indentText == IndentText ? DoNotIndentText : IndentText; 1083 indentText = indentText == IndentText ? DoNotIndentText : IndentText;
984 1084
985 return indentText; 1085 return indentText;
986 } 1086 }
987 1087
988 } // namespace blink 1088 } // namespace blink
989 1089
990 #endif // BreakingContextInlineHeaders_h 1090 #endif // BreakingContextInlineHeaders_h
OLDNEW
« no previous file with comments | « third_party/WebKit/LayoutTests/fast/text/break-word-pre-wrap-expected.html ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698