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 |