Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 109 InlineIterator handleEndOfLine(); | 109 InlineIterator handleEndOfLine(); |
| 110 | 110 |
| 111 void clearLineBreakIfFitsOnLine() | 111 void clearLineBreakIfFitsOnLine() |
| 112 { | 112 { |
| 113 if (m_width.fitsOnLine() || m_lastWS == NOWRAP) | 113 if (m_width.fitsOnLine() || m_lastWS == NOWRAP) |
| 114 m_lineBreak.clear(); | 114 m_lineBreak.clear(); |
| 115 } | 115 } |
| 116 | 116 |
| 117 private: | 117 private: |
| 118 void skipTrailingWhitespace(InlineIterator&, const LineInfo&); | 118 void skipTrailingWhitespace(InlineIterator&, const LineInfo&); |
| 119 bool shouldMidWordBreak(UChar, LineLayoutText, const Font&, | |
| 120 float& charWidth, float& widthFromLastBreakingOpportunity, | |
| 121 bool breakAll, int& nextBreakablePositionForBreakAll); | |
| 119 bool rewindToMidWordBreak(WordMeasurement&, int end, float width); | 122 bool rewindToMidWordBreak(WordMeasurement&, int end, float width); |
| 120 bool rewindToFirstMidWordBreak(LineLayoutText, const ComputedStyle&, const F ont&, bool breakAll, WordMeasurement&); | 123 bool rewindToFirstMidWordBreak(LineLayoutText, const ComputedStyle&, const F ont&, bool breakAll, WordMeasurement&); |
| 121 bool rewindToMidWordBreak(LineLayoutText, const ComputedStyle&, const Font&, bool breakAll, WordMeasurement&); | 124 bool rewindToMidWordBreak(LineLayoutText, const ComputedStyle&, const Font&, bool breakAll, WordMeasurement&); |
| 122 bool hyphenate(LineLayoutText, const ComputedStyle&, const Font&, const Hyph enation&, float lastSpaceWordSpacing, WordMeasurement&); | 125 bool hyphenate(LineLayoutText, const ComputedStyle&, const Font&, const Hyph enation&, float lastSpaceWordSpacing, WordMeasurement&); |
| 123 | 126 |
| 124 InlineBidiResolver& m_resolver; | 127 InlineBidiResolver& m_resolver; |
| 125 | 128 |
| 126 InlineIterator m_current; | 129 InlineIterator m_current; |
| 127 InlineIterator m_lineBreak; | 130 InlineIterator m_lineBreak; |
| 128 InlineIterator m_startOfIgnoredSpaces; | 131 InlineIterator m_startOfIgnoredSpaces; |
| (...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 535 { | 538 { |
| 536 if ((!from && len == text.textLength()) || text.style()->hasTextCombine()) | 539 if ((!from && len == text.textLength()) || text.style()->hasTextCombine()) |
| 537 return text.width(from, len, font, LayoutUnit(xPos), text.style()->direc tion(), fallbackFonts, glyphBounds); | 540 return text.width(from, len, font, LayoutUnit(xPos), text.style()->direc tion(), fallbackFonts, glyphBounds); |
| 538 | 541 |
| 539 TextRun run = constructTextRun(font, text, from, len, text.styleRef()); | 542 TextRun run = constructTextRun(font, text, from, len, text.styleRef()); |
| 540 run.setTabSize(!collapseWhiteSpace, text.style()->getTabSize()); | 543 run.setTabSize(!collapseWhiteSpace, text.style()->getTabSize()); |
| 541 run.setXPos(xPos); | 544 run.setXPos(xPos); |
| 542 return font.width(run, fallbackFonts, glyphBounds); | 545 return font.width(run, fallbackFonts, glyphBounds); |
| 543 } | 546 } |
| 544 | 547 |
| 548 ALWAYS_INLINE bool BreakingContext::shouldMidWordBreak( | |
| 549 UChar c, LineLayoutText layoutText, const Font& font, | |
| 550 float& charWidth, float& widthFromLastBreakingOpportunity, | |
| 551 bool breakAll, int& nextBreakablePositionForBreakAll) | |
| 552 { | |
| 553 // For breakWords/breakAll, we need to measure up to normal break | |
| 554 // opportunity and then rewindToMidWordBreak() because ligatures/kerning can | |
| 555 // shorten the width as we add more characters. | |
| 556 // However, doing so can hit the performance when a "word" is really long, | |
| 557 // such as minimized JS, because the next line will re-shape the rest of the | |
| 558 // word in the current architecture. | |
| 559 // This function is a heuristic optimization to stop at 2em overflow. | |
| 560 float overflowAllowance = 2 * font.getFontDescription().computedSize(); | |
| 561 | |
| 562 widthFromLastBreakingOpportunity += charWidth; | |
| 563 bool midWordBreakIsBeforeSurrogatePair = U16_IS_LEAD(c) && m_current.offset( ) + 1 < layoutText.textLength() && U16_IS_TRAIL(layoutText.uncheckedCharacterAt( m_current.offset() + 1)); | |
| 564 charWidth = textWidth(layoutText, m_current.offset(), midWordBreakIsBeforeSu rrogatePair ? 2 : 1, font, m_width.committedWidth() + widthFromLastBreakingOppor tunity, m_collapseWhiteSpace); | |
| 565 if (m_width.committedWidth() + widthFromLastBreakingOpportunity + charWidth <= m_width.availableWidth() + overflowAllowance) | |
| 566 return false; | |
| 567 | |
|
kojii
2016/07/05 11:37:58
Up to this point in this function is just a move f
| |
| 568 // breakAll has different break opportunities. Ensure we break only at | |
| 569 // breakAll allows to break. | |
| 570 if (breakAll && | |
| 571 !m_layoutTextInfo.m_lineBreakIterator.isBreakable(m_current.offset(), ne xtBreakablePositionForBreakAll, LineBreakType::BreakAll)) { | |
| 572 return false; | |
| 573 } | |
| 574 | |
| 575 return true; | |
| 576 } | |
| 577 | |
| 545 ALWAYS_INLINE int lastBreakablePositionForBreakAll(LineLayoutText text, | 578 ALWAYS_INLINE int lastBreakablePositionForBreakAll(LineLayoutText text, |
| 546 const ComputedStyle& style, int start, int end) | 579 const ComputedStyle& style, int start, int end) |
| 547 { | 580 { |
| 548 LazyLineBreakIterator lineBreakIterator(text.text(), style.locale()); | 581 LazyLineBreakIterator lineBreakIterator(text.text(), style.locale()); |
| 549 int lastBreakablePosition = 0, nextBreakablePosition = -1; | 582 int lastBreakablePosition = 0, nextBreakablePosition = -1; |
| 550 for (int i = start; ;i = nextBreakablePosition + 1) { | 583 for (int i = start; ;i = nextBreakablePosition + 1) { |
| 551 lineBreakIterator.isBreakable(i, nextBreakablePosition, LineBreakType::B reakAll); | 584 lineBreakIterator.isBreakable(i, nextBreakablePosition, LineBreakType::B reakAll); |
| 552 if (nextBreakablePosition == end) | 585 if (nextBreakablePosition == end) |
| 553 return end; | 586 return end; |
| 554 if (nextBreakablePosition < 0 || nextBreakablePosition > end) | 587 if (nextBreakablePosition < 0 || nextBreakablePosition > end) |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 708 if (layoutText.isSVGInlineText()) { | 741 if (layoutText.isSVGInlineText()) { |
| 709 breakWords = false; | 742 breakWords = false; |
| 710 breakAll = false; | 743 breakAll = false; |
| 711 keepAll = false; | 744 keepAll = false; |
| 712 } | 745 } |
| 713 | 746 |
| 714 // Use LineBreakType::Normal for break-all. When a word does not fit, | 747 // Use LineBreakType::Normal for break-all. When a word does not fit, |
| 715 // rewindToMidWordBreak() finds the mid-word break point. | 748 // rewindToMidWordBreak() finds the mid-word break point. |
| 716 LineBreakType lineBreakType = keepAll ? LineBreakType::KeepAll : LineBreakTy pe::Normal; | 749 LineBreakType lineBreakType = keepAll ? LineBreakType::KeepAll : LineBreakTy pe::Normal; |
| 717 bool canBreakMidWord = breakAll || breakWords; | 750 bool canBreakMidWord = breakAll || breakWords; |
| 751 int nextBreakablePositionForBreakAll = -1; | |
| 718 | 752 |
| 719 if (layoutText.isWordBreak()) { | 753 if (layoutText.isWordBreak()) { |
| 720 m_width.commit(); | 754 m_width.commit(); |
| 721 m_lineBreak.moveToStartOf(m_current.getLineLayoutItem()); | 755 m_lineBreak.moveToStartOf(m_current.getLineLayoutItem()); |
| 722 ASSERT(m_current.offset() == layoutText.textLength()); | 756 ASSERT(m_current.offset() == layoutText.textLength()); |
| 723 } | 757 } |
| 724 | 758 |
| 725 if (m_layoutTextInfo.m_text != layoutText) { | 759 if (m_layoutTextInfo.m_text != layoutText) { |
| 726 m_layoutTextInfo.m_text = layoutText; | 760 m_layoutTextInfo.m_text = layoutText; |
| 727 m_layoutTextInfo.m_font = &font; | 761 m_layoutTextInfo.m_font = &font; |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 749 } | 783 } |
| 750 | 784 |
| 751 if (c == softHyphenCharacter && m_autoWrap && !hyphenWidth && !disableSo ftHyphen) { | 785 if (c == softHyphenCharacter && m_autoWrap && !hyphenWidth && !disableSo ftHyphen) { |
| 752 hyphenWidth = layoutText.hyphenWidth(font, textDirectionFromUnicode( m_resolver.position().direction())); | 786 hyphenWidth = layoutText.hyphenWidth(font, textDirectionFromUnicode( m_resolver.position().direction())); |
| 753 m_width.addUncommittedWidth(hyphenWidth); | 787 m_width.addUncommittedWidth(hyphenWidth); |
| 754 } | 788 } |
| 755 | 789 |
| 756 bool applyWordSpacing = false; | 790 bool applyWordSpacing = false; |
| 757 | 791 |
| 758 // Determine if we should try breaking in the middle of a word. | 792 // Determine if we should try breaking in the middle of a word. |
| 759 if (breakWords && !midWordBreak && !U16_IS_TRAIL(c)) { | 793 if (canBreakMidWord && !midWordBreak && !U16_IS_TRAIL(c)) |
| 760 widthFromLastBreakingOpportunity += charWidth; | 794 midWordBreak = shouldMidWordBreak(c, layoutText, font, charWidth, wi dthFromLastBreakingOpportunity, breakAll, nextBreakablePositionForBreakAll); |
| 761 bool midWordBreakIsBeforeSurrogatePair = U16_IS_LEAD(c) && m_current .offset() + 1 < layoutText.textLength() && U16_IS_TRAIL(layoutText.uncheckedChar acterAt(m_current.offset() + 1)); | |
| 762 charWidth = textWidth(layoutText, m_current.offset(), midWordBreakIs BeforeSurrogatePair ? 2 : 1, font, m_width.committedWidth() + widthFromLastBreak ingOpportunity, m_collapseWhiteSpace); | |
| 763 // Measure up to 2em overflow since ligatures/kerning can shorten | |
| 764 // the width as we add more characters. rewindToMidWordBreak() can | |
| 765 // measure the accurate mid-word break point then. | |
| 766 midWordBreak = m_width.committedWidth() + widthFromLastBreakingOppor tunity + charWidth > m_width.availableWidth() | |
| 767 + 2 * font.getFontDescription().computedSize(); | |
| 768 } | |
| 769 | 795 |
| 770 // Determine if we are in the whitespace between words. | 796 // Determine if we are in the whitespace between words. |
| 771 int nextBreakablePosition = m_current.nextBreakablePosition(); | 797 int nextBreakablePosition = m_current.nextBreakablePosition(); |
| 772 bool betweenWords = c == newlineCharacter || (m_currWS != PRE && !m_atSt art && m_layoutTextInfo.m_lineBreakIterator.isBreakable(m_current.offset(), next BreakablePosition, lineBreakType) | 798 bool betweenWords = c == newlineCharacter || (m_currWS != PRE && !m_atSt art && m_layoutTextInfo.m_lineBreakIterator.isBreakable(m_current.offset(), next BreakablePosition, lineBreakType) |
| 773 && (!disableSoftHyphen || m_current.previousInSameNode() != softHyph enCharacter)); | 799 && (!disableSoftHyphen || m_current.previousInSameNode() != softHyph enCharacter)); |
| 774 m_current.setNextBreakablePosition(nextBreakablePosition); | 800 m_current.setNextBreakablePosition(nextBreakablePosition); |
| 775 | 801 |
| 776 // 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. | 802 // 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. |
| 777 if (!betweenWords && !midWordBreak) { | 803 if (!betweenWords && !midWordBreak) { |
| 778 if (m_ignoringSpaces) { | 804 if (m_ignoringSpaces) { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 820 m_width.setTrailingWhitespaceWidth(lastWidthMeasurement); | 846 m_width.setTrailingWhitespaceWidth(lastWidthMeasurement); |
| 821 | 847 |
| 822 // If this is the end of the first word in run of text then make sure we apply the width from any leading inlines. | 848 // If this is the end of the first word in run of text then make sure we apply the width from any leading inlines. |
| 823 // For example: '<span style="margin-left: 5px;"><span style="margin-lef t: 10px;">FirstWord</span></span>' would | 849 // For example: '<span style="margin-left: 5px;"><span style="margin-lef t: 10px;">FirstWord</span></span>' would |
| 824 // apply a width of 15px from the two span ancestors. | 850 // apply a width of 15px from the two span ancestors. |
| 825 if (!m_appliedStartWidth) { | 851 if (!m_appliedStartWidth) { |
| 826 m_width.addUncommittedWidth(inlineLogicalWidthFromAncestorsIfNeeded( m_current.getLineLayoutItem(), true, false).toFloat()); | 852 m_width.addUncommittedWidth(inlineLogicalWidthFromAncestorsIfNeeded( m_current.getLineLayoutItem(), true, false).toFloat()); |
| 827 m_appliedStartWidth = true; | 853 m_appliedStartWidth = true; |
| 828 } | 854 } |
| 829 | 855 |
| 830 // If we haven't hit a breakable position yet and already don't fit on t he line try to move below any floats. | |
| 831 if (!m_width.committedWidth() && m_autoWrap && !m_width.fitsOnLine() && !widthMeasurementAtLastBreakOpportunity) | |
| 832 m_width.fitBelowFloats(m_lineInfo.isFirstLine()); | |
| 833 | |
| 834 midWordBreak = false; | 856 midWordBreak = false; |
| 835 if (!m_width.fitsOnLine()) { | 857 if (!m_width.fitsOnLine()) { |
| 836 if (canBreakMidWord) { | 858 if (canBreakMidWord) { |
| 837 m_width.addUncommittedWidth(-wordMeasurement.width); | 859 m_width.addUncommittedWidth(-wordMeasurement.width); |
| 838 if (rewindToMidWordBreak(layoutText, style, font, breakAll, word Measurement)) { | 860 if (rewindToMidWordBreak(layoutText, style, font, breakAll, word Measurement)) { |
| 839 lastWidthMeasurement = wordMeasurement.width + lastSpaceWord Spacing; | 861 lastWidthMeasurement = wordMeasurement.width + lastSpaceWord Spacing; |
| 840 midWordBreak = true; | 862 midWordBreak = true; |
| 841 } | 863 } |
| 842 m_width.addUncommittedWidth(wordMeasurement.width); | 864 m_width.addUncommittedWidth(wordMeasurement.width); |
| 843 } else if (hyphenation) { | 865 } else if (hyphenation) { |
| 844 m_width.addUncommittedWidth(-wordMeasurement.width); | 866 m_width.addUncommittedWidth(-wordMeasurement.width); |
| 845 DCHECK(lastSpace == static_cast<unsigned>(wordMeasurement.startO ffset)); | 867 DCHECK(lastSpace == static_cast<unsigned>(wordMeasurement.startO ffset)); |
| 846 DCHECK(m_current.offset() == static_cast<unsigned>(wordMeasureme nt.endOffset)); | 868 DCHECK(m_current.offset() == static_cast<unsigned>(wordMeasureme nt.endOffset)); |
| 847 if (hyphenate(layoutText, style, font, *hyphenation, lastSpaceWo rdSpacing, wordMeasurement)) { | 869 if (hyphenate(layoutText, style, font, *hyphenation, lastSpaceWo rdSpacing, wordMeasurement)) { |
| 848 m_width.addUncommittedWidth(wordMeasurement.width); | 870 m_width.addUncommittedWidth(wordMeasurement.width); |
| 849 hyphenated = true; | 871 hyphenated = true; |
| 850 m_atEnd = true; | 872 m_atEnd = true; |
| 851 return false; | 873 return false; |
| 852 } | 874 } |
| 853 m_width.addUncommittedWidth(wordMeasurement.width); | 875 m_width.addUncommittedWidth(wordMeasurement.width); |
| 854 } | 876 } |
| 855 } | 877 } |
| 856 | 878 |
| 879 // If we haven't hit a breakable position yet and already don't fit on t he line try to move below any floats. | |
| 880 if (!m_width.committedWidth() && m_autoWrap && !m_width.fitsOnLine() && !widthMeasurementAtLastBreakOpportunity) { | |
| 881 float availableWidthBefore = m_width.availableWidth(); | |
| 882 m_width.fitBelowFloats(m_lineInfo.isFirstLine()); | |
| 883 // If availableWidth changes by moving the line below floats, needs to measure midWordBreak again. | |
| 884 if (midWordBreak && availableWidthBefore != m_width.availableWidth() ) | |
| 885 midWordBreak = false; | |
| 886 } | |
|
kojii
2016/07/05 11:37:58
Doing this before rewindToMidWordBreak was the pre
| |
| 887 | |
| 857 // If there is a soft-break available at this whitespace position then t ake it. | 888 // If there is a soft-break available at this whitespace position then t ake it. |
| 858 applyWordSpacing = wordSpacing && m_currentCharacterIsSpace; | 889 applyWordSpacing = wordSpacing && m_currentCharacterIsSpace; |
| 859 if (canBreakAtWhitespace(breakWords, wordMeasurement, stoppedIgnoringSpa ces, charWidth, hyphenated, disableSoftHyphen, hyphenWidth, betweenWords, midWor dBreak, canBreakMidWord, previousCharacterIsSpace, lastWidthMeasurement, layoutT ext, font, applyWordSpacing, wordSpacing)) | 890 if (canBreakAtWhitespace(breakWords, wordMeasurement, stoppedIgnoringSpa ces, charWidth, hyphenated, disableSoftHyphen, hyphenWidth, betweenWords, midWor dBreak, canBreakMidWord, previousCharacterIsSpace, lastWidthMeasurement, layoutT ext, font, applyWordSpacing, wordSpacing)) |
| 860 return false; | 891 return false; |
| 861 | 892 |
| 862 // If there is a hard-break available at this whitespace position then t ake it. | 893 // If there is a hard-break available at this whitespace position then t ake it. |
| 863 if (c == newlineCharacter && m_preservesNewline) { | 894 if (c == newlineCharacter && m_preservesNewline) { |
| 864 if (!stoppedIgnoringSpaces && m_current.offset()) | 895 if (!stoppedIgnoringSpaces && m_current.offset()) |
| 865 m_lineMidpointState.ensureCharacterGetsLineBox(m_current); | 896 m_lineMidpointState.ensureCharacterGetsLineBox(m_current); |
| 866 m_lineBreak.moveTo(m_current.getLineLayoutItem(), m_current.offset() , m_current.nextBreakablePosition()); | 897 m_lineBreak.moveTo(m_current.getLineLayoutItem(), m_current.offset() , m_current.nextBreakablePosition()); |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1152 | 1183 |
| 1153 if (style.getTextIndentType() == TextIndentHanging) | 1184 if (style.getTextIndentType() == TextIndentHanging) |
| 1154 indentText = indentText == IndentText ? DoNotIndentText : IndentText; | 1185 indentText = indentText == IndentText ? DoNotIndentText : IndentText; |
| 1155 | 1186 |
| 1156 return indentText; | 1187 return indentText; |
| 1157 } | 1188 } |
| 1158 | 1189 |
| 1159 } // namespace blink | 1190 } // namespace blink |
| 1160 | 1191 |
| 1161 #endif // BreakingContextInlineHeaders_h | 1192 #endif // BreakingContextInlineHeaders_h |
| OLD | NEW |