Chromium Code Reviews| Index: third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h |
| diff --git a/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h b/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h |
| index 68da4d7afdd3e19bac0e64a4a266bb826418b1d1..efdbf69d8fe470287455f8b18229ee203815248f 100644 |
| --- a/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h |
| +++ b/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h |
| @@ -72,7 +72,7 @@ public: |
| , m_atStart(true) |
| , m_ignoringSpaces(false) |
| , m_currentCharacterIsSpace(false) |
| - , m_currentCharacterShouldCollapseIfPreWap(false) |
| + , m_currentCharacterShouldCollapseIfPreWrap(false) |
| , m_appliedStartWidth(appliedStartWidth) |
| , m_includeEndWidth(true) |
| , m_autoWrap(false) |
| @@ -101,6 +101,11 @@ public: |
| void handleEmptyInline(); |
| void handleReplaced(); |
| bool handleText(WordMeasurements&, bool& hyphenated); |
| + void prepareForNextCharacter(const LineLayoutText&, bool& prohibitBreakInside, bool previousCharacterIsSpace, bool previousCharacterShouldCollapseIfPreWap); |
| + bool canBreakAtWhitespace(bool breakWords, WordMeasurement&, bool stoppedIgnoringSpaces, bool& hyphenated, float charWidth, float& hyphenWidth, bool betweenWords, bool midWordBreak, bool breakAll, bool previousCharacterIsSpace, float lastWidthMeasurement, const LineLayoutText&, const Font&, bool applyWordSpacing, float wordSpacing); |
| + bool trailingSpaceExceedsAvailableWidth(bool midWordBreak, const LineLayoutText&, WordMeasurement&, bool applyWordSpacing, bool wordSpacing, const Font&); |
| + WordMeasurement& calculateWordWidth(WordMeasurements&, LineLayoutText&, float lastSpace, float& lastWidthMeasurement, float wordSpacingForWordMeasurement, const Font&, float wordTrailingSpaceWidth, UChar); |
| + void stopIgnoringSpaces(unsigned& lastSpace); |
| void commitAndUpdateLineBreakIfNeeded(); |
| InlineIterator handleEndOfLine(); |
| @@ -141,7 +146,7 @@ private: |
| bool m_atStart; |
| bool m_ignoringSpaces; |
| bool m_currentCharacterIsSpace; |
| - bool m_currentCharacterShouldCollapseIfPreWap; |
| + bool m_currentCharacterShouldCollapseIfPreWrap; |
| bool m_appliedStartWidth; |
| bool m_includeEndWidth; |
| bool m_autoWrap; |
| @@ -449,7 +454,7 @@ inline void BreakingContext::handleEmptyInline() |
| && shouldSkipWhitespaceAfterStartObject(m_block, m_current.object(), m_lineMidpointState)) { |
| // If this object is at the start of the line, we need to behave like list markers and |
| // start ignoring spaces. |
| - m_currentCharacterShouldCollapseIfPreWap = m_currentCharacterIsSpace = true; |
| + m_currentCharacterShouldCollapseIfPreWrap = m_currentCharacterIsSpace = true; |
| m_ignoringSpaces = true; |
| } else { |
| // If we are after a trailing space but aren't ignoring spaces yet then ensure we get a linebox |
| @@ -481,7 +486,7 @@ inline void BreakingContext::handleReplaced() |
| m_lineInfo.setEmpty(false, m_block, &m_width); |
| m_ignoringSpaces = false; |
| - m_currentCharacterShouldCollapseIfPreWap = m_currentCharacterIsSpace = false; |
| + m_currentCharacterShouldCollapseIfPreWrap = m_currentCharacterIsSpace = false; |
| m_trailingObjects.clear(); |
| // Optimize for a common case. If we can't find whitespace after the list |
| @@ -491,7 +496,7 @@ inline void BreakingContext::handleReplaced() |
| if (m_blockStyle->collapseWhiteSpace() && shouldSkipWhitespaceAfterStartObject(m_block, m_current.object(), m_lineMidpointState)) { |
| // Like with inline flows, we start ignoring spaces to make sure that any |
| // additional spaces we see will be discarded. |
| - m_currentCharacterShouldCollapseIfPreWap = m_currentCharacterIsSpace = true; |
| + m_currentCharacterShouldCollapseIfPreWrap = m_currentCharacterIsSpace = true; |
| m_ignoringSpaces = true; |
| } |
| if (LineLayoutListMarker(m_current.object()).isInside()) |
| @@ -545,8 +550,6 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool |
| LineLayoutText layoutText(m_current.object()); |
| - bool isSVGText = layoutText.isSVGInlineText(); |
| - |
| // If we have left a no-wrap inline and entered an autowrap inline while ignoring spaces |
| // then we need to mark the start of the autowrap inline as a potential linebreak now. |
| if (m_autoWrap && !ComputedStyle::autoWrap(m_lastWS) && m_ignoringSpaces) { |
| @@ -580,7 +583,7 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool |
| float hyphenWidth = 0; |
| - if (isSVGText) { |
| + if (layoutText.isSVGInlineText()) { |
| breakWords = false; |
| breakAll = false; |
| keepAll = false; |
| @@ -610,9 +613,9 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool |
| UChar secondToLastCharacter = m_layoutTextInfo.m_lineBreakIterator.secondToLastCharacter(); |
| for (; m_current.offset() < layoutText.textLength(); m_current.fastIncrementInTextNode()) { |
| bool previousCharacterIsSpace = m_currentCharacterIsSpace; |
| - bool previousCharacterShouldCollapseIfPreWap = m_currentCharacterShouldCollapseIfPreWap; |
| + bool previousCharacterShouldCollapseIfPreWap = m_currentCharacterShouldCollapseIfPreWrap; |
| UChar c = m_current.current(); |
| - m_currentCharacterShouldCollapseIfPreWap = m_currentCharacterIsSpace = c == spaceCharacter || c == tabulationCharacter || (!m_preservesNewline && (c == newlineCharacter)); |
| + m_currentCharacterShouldCollapseIfPreWrap = m_currentCharacterIsSpace = c == spaceCharacter || c == tabulationCharacter || (!m_preservesNewline && (c == newlineCharacter)); |
| if (!m_collapseWhiteSpace || !m_currentCharacterIsSpace) |
| m_lineInfo.setEmpty(false, m_block, &m_width); |
| @@ -624,6 +627,7 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool |
| bool applyWordSpacing = false; |
| + // Determine if we should try breaking in the middle of a word. |
| if (breakWords && !midWordBreak) { |
| widthFromLastBreakingOpportunity += charWidth; |
| bool midWordBreakIsBeforeSurrogatePair = U16_IS_LEAD(c) && m_current.offset() + 1 < layoutText.textLength() && U16_IS_TRAIL(layoutText.uncheckedCharacterAt(m_current.offset() + 1)); |
| @@ -631,191 +635,114 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool |
| midWordBreak = m_width.committedWidth() + widthFromLastBreakingOpportunity + charWidth > m_width.availableWidth(); |
| } |
| + // Determine if we are in the whitespace between words. |
| int nextBreakablePosition = m_current.nextBreakablePosition(); |
| bool betweenWords = c == newlineCharacter || (m_currWS != PRE && !m_atStart && m_layoutTextInfo.m_lineBreakIterator.isBreakable(m_current.offset(), nextBreakablePosition, breakAll ? LineBreakType::BreakAll : keepAll ? LineBreakType::KeepAll : LineBreakType::Normal)); |
| m_current.setNextBreakablePosition(nextBreakablePosition); |
| - if (betweenWords || midWordBreak) { |
| - bool stoppedIgnoringSpaces = false; |
| + // 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. |
| + if (!betweenWords && !midWordBreak) { |
| if (m_ignoringSpaces) { |
| - lastSpaceWordSpacing = 0; |
| - if (!m_currentCharacterIsSpace) { |
| - // Stop ignoring spaces and begin at this |
| - // new point. |
| - m_ignoringSpaces = false; |
| - wordSpacingForWordMeasurement = 0; |
| - lastSpace = m_current.offset(); // e.g., "Foo goo", don't add in any of the ignored spaces. |
| - m_lineMidpointState.stopIgnoringSpaces(InlineIterator(0, m_current.object(), m_current.offset())); |
| - stoppedIgnoringSpaces = true; |
| - } else { |
| - // Just keep ignoring these spaces. |
| - nextCharacter(c, lastCharacter, secondToLastCharacter); |
| - continue; |
| - } |
| - } |
| - |
| - wordMeasurements.grow(wordMeasurements.size() + 1); |
| - WordMeasurement& wordMeasurement = wordMeasurements.last(); |
| - |
| - wordMeasurement.layoutText = layoutText; |
| - wordMeasurement.endOffset = m_current.offset(); |
| - wordMeasurement.startOffset = lastSpace; |
| - |
| - float lastWidthMeasurement; |
| - if (wordTrailingSpaceWidth && c == spaceCharacter) |
| - lastWidthMeasurement = textWidth(layoutText, lastSpace, m_current.offset() + 1 - lastSpace, font, m_width.currentWidth(), m_collapseWhiteSpace, &wordMeasurement.fallbackFonts, &wordMeasurement.glyphBounds) - wordTrailingSpaceWidth; |
| - else |
| - lastWidthMeasurement = textWidth(layoutText, lastSpace, m_current.offset() - lastSpace, font, m_width.currentWidth(), m_collapseWhiteSpace, &wordMeasurement.fallbackFonts, &wordMeasurement.glyphBounds); |
| - |
| - wordMeasurement.width = lastWidthMeasurement + wordSpacingForWordMeasurement; |
| - wordMeasurement.glyphBounds.move(wordSpacingForWordMeasurement, 0); |
| - lastWidthMeasurement += lastSpaceWordSpacing; |
| - m_width.addUncommittedWidth(lastWidthMeasurement); |
| - |
| - if (m_collapseWhiteSpace && previousCharacterIsSpace && m_currentCharacterIsSpace && lastWidthMeasurement) |
| - m_width.setTrailingWhitespaceWidth(lastWidthMeasurement); |
| - |
| - if (!m_appliedStartWidth) { |
| - m_width.addUncommittedWidth(inlineLogicalWidthFromAncestorsIfNeeded(m_current.object(), true, false).toFloat()); |
| - m_appliedStartWidth = true; |
| + lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0; |
| + wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurements.last().width) ? wordSpacing : 0; |
| + stopIgnoringSpaces(lastSpace); |
| } |
| + prepareForNextCharacter(layoutText, prohibitBreakInside, previousCharacterIsSpace, previousCharacterShouldCollapseIfPreWap); |
| + m_atStart = false; |
| + nextCharacter(c, lastCharacter, secondToLastCharacter); |
| + continue; |
| + } |
| - applyWordSpacing = wordSpacing && m_currentCharacterIsSpace; |
| + // If we're ignoring space and we're at a collapsible space such as a space or tab, continue to the next character. |
| + bool stoppedIgnoringSpaces = false; |
| + if (m_ignoringSpaces && m_currentCharacterIsSpace) { |
| + lastSpaceWordSpacing = 0; |
| + // Just keep ignoring these spaces. |
| + nextCharacter(c, lastCharacter, secondToLastCharacter); |
| + continue; |
| + } |
| - if (!m_width.committedWidth() && m_autoWrap && !m_width.fitsOnLine() && !widthMeasurementAtLastBreakOpportunity) |
| - m_width.fitBelowFloats(m_lineInfo.isFirstLine()); |
| + // So we're in the first whitespace after a word or in whitespace that we don't collapse, which means we may have a breaking opportunity here. |
| - if (m_autoWrap || breakWords) { |
| - // If we break only after white-space, consider the current character |
| - // as candidate width for this line. |
| - bool lineWasTooWide = false; |
| - if (m_width.fitsOnLine() && m_currentCharacterIsSpace && m_currentStyle->breakOnlyAfterWhiteSpace() && !midWordBreak) { |
| - float charWidth = textWidth(layoutText, m_current.offset(), 1, font, m_width.currentWidth(), m_collapseWhiteSpace, &wordMeasurement.fallbackFonts, &wordMeasurement.glyphBounds) + (applyWordSpacing ? wordSpacing : 0); |
| - // Check if line is too big even without the extra space |
| - // at the end of the line. If it is not, do nothing. |
| - // If the line needs the extra whitespace to be too long, |
| - // then move the line break to the space and skip all |
| - // additional whitespace. |
| - if (!m_width.fitsOnLine(charWidth)) { |
| - lineWasTooWide = true; |
| - m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition()); |
| - skipTrailingWhitespace(m_lineBreak, m_lineInfo); |
| - } |
| - } |
| - if (lineWasTooWide || !m_width.fitsOnLine()) { |
| - if (m_lineBreak.atTextParagraphSeparator()) { |
| - if (!stoppedIgnoringSpaces && m_current.offset() > 0) |
| - m_lineMidpointState.ensureCharacterGetsLineBox(m_current); |
| - m_lineBreak.increment(); |
| - m_lineInfo.setPreviousLineBrokeCleanly(true); |
| - wordMeasurement.endOffset = m_lineBreak.offset(); |
| - } |
| - if (m_lineBreak.object() && m_lineBreak.offset() && m_lineBreak.object().isText() && LineLayoutText(m_lineBreak.object()).textLength() && LineLayoutText(m_lineBreak.object()).characterAt(m_lineBreak.offset() - 1) == softHyphenCharacter) |
| - hyphenated = true; |
| - if (m_lineBreak.offset() && m_lineBreak.offset() != (unsigned)wordMeasurement.endOffset && !wordMeasurement.width) { |
| - if (charWidth) { |
| - wordMeasurement.endOffset = m_lineBreak.offset(); |
| - wordMeasurement.width = charWidth; |
| - } |
| - } |
| - // Didn't fit. Jump to the end unless there's still an opportunity to collapse whitespace. |
| - if (m_ignoringSpaces || !m_collapseWhiteSpace || !m_currentCharacterIsSpace || !previousCharacterIsSpace) { |
| - m_atEnd = true; |
| - return false; |
| - } |
| - } else { |
| - if (!betweenWords || (midWordBreak && !m_autoWrap) || (breakAll && !m_currentCharacterIsSpace)) |
| - m_width.addUncommittedWidth(-lastWidthMeasurement); |
| - if (hyphenWidth) { |
| - // Subtract the width of the soft hyphen out since we fit on a line. |
| - m_width.addUncommittedWidth(-hyphenWidth); |
| - hyphenWidth = 0; |
| - } |
| - } |
| - } |
| + // If we're here and we're ignoring spaces then the current character isn't a space, it's some of other form of whitespace. Stop ignoring spaces. |
| + if (m_ignoringSpaces) { |
| + lastSpaceWordSpacing = 0; |
| + wordSpacingForWordMeasurement = 0; |
| + stoppedIgnoringSpaces = true; |
| + stopIgnoringSpaces(lastSpace); |
| + } |
| - if (c == newlineCharacter && m_preservesNewline) { |
| - if (!stoppedIgnoringSpaces && m_current.offset()) |
| - m_lineMidpointState.ensureCharacterGetsLineBox(m_current); |
| - m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition()); |
| - m_lineBreak.increment(); |
| - m_lineInfo.setPreviousLineBrokeCleanly(true); |
| - return true; |
| - } |
| + // Update our tally of the width since the last breakable position with the width of the word we're now at the end of. |
| + float lastWidthMeasurement; |
| + WordMeasurement& wordMeasurement = calculateWordWidth(wordMeasurements, layoutText, lastSpace, lastWidthMeasurement, wordSpacingForWordMeasurement, font, wordTrailingSpaceWidth, c); |
| + lastWidthMeasurement += lastSpaceWordSpacing; |
| + m_width.addUncommittedWidth(lastWidthMeasurement); |
| + |
| + // We keep track of the total width contributed by trailing space as we often want to exclude it when determining |
| + // if a run fits on a line. |
| + if (m_collapseWhiteSpace && previousCharacterIsSpace && m_currentCharacterIsSpace && lastWidthMeasurement) |
| + m_width.setTrailingWhitespaceWidth(lastWidthMeasurement); |
| + |
| + // If this is the end of the first word in run of text then make sure we apply the width from any leading inlines. |
| + // For example: '<span style="margin-left: 5px;"><span style="margin-left: 10px;">FirstWord</span></span>' would |
| + // apply a width of 15px from the two span ancestors. |
| + if (!m_appliedStartWidth) { |
| + m_width.addUncommittedWidth(inlineLogicalWidthFromAncestorsIfNeeded(m_current.object(), true, false).toFloat()); |
| + m_appliedStartWidth = true; |
| + } |
| - if (m_autoWrap && betweenWords) { |
| - m_width.commit(); |
| - widthFromLastBreakingOpportunity = 0; |
| - m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition()); |
| - // Auto-wrapping text should not wrap in the middle of a word once it has had an |
| - // opportunity to break after a word. |
| - breakWords = false; |
| - widthMeasurementAtLastBreakOpportunity = lastWidthMeasurement; |
| - } |
| + // If we haven't hit a breakable position yet and already don't fit on the line try to move below any floats. |
| + if (!m_width.committedWidth() && m_autoWrap && !m_width.fitsOnLine() && !widthMeasurementAtLastBreakOpportunity) |
| + m_width.fitBelowFloats(m_lineInfo.isFirstLine()); |
| - if (midWordBreak && !U16_IS_TRAIL(c) && !(WTF::Unicode::category(c) & (WTF::Unicode::Mark_NonSpacing | WTF::Unicode::Mark_Enclosing | WTF::Unicode::Mark_SpacingCombining))) { |
| - // Remember this as a breakable position in case |
| - // adding the end width forces a break. |
| - m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition()); |
| - midWordBreak &= (breakWords || breakAll); |
| - } |
| + // If there is a soft-break available at this whitespace position then take it. |
| + applyWordSpacing = wordSpacing && m_currentCharacterIsSpace; |
| + if (canBreakAtWhitespace(breakWords, wordMeasurement, stoppedIgnoringSpaces, hyphenated, charWidth, hyphenWidth, betweenWords, midWordBreak, breakAll, previousCharacterIsSpace, lastWidthMeasurement, layoutText, font, applyWordSpacing, wordSpacing)) |
| + return false; |
| - if (betweenWords) { |
| - lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0; |
| - wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurement.width) ? wordSpacing : 0; |
| - lastSpace = !breakAll || m_currentCharacterIsSpace ? m_current.offset() : lastSpace; |
| - } |
| - |
| - if (!m_ignoringSpaces && m_currentStyle->collapseWhiteSpace()) { |
| - // If we encounter a newline, or if we encounter a |
| - // second space, we need to go ahead and break up this |
| - // run and enter a mode where we start collapsing spaces. |
| - if (m_currentCharacterIsSpace && previousCharacterIsSpace) { |
| - m_ignoringSpaces = true; |
| - |
| - // We just entered a mode where we are ignoring |
| - // spaces. Create a midpoint to terminate the run |
| - // before the second space. |
| - m_lineMidpointState.startIgnoringSpaces(m_startOfIgnoredSpaces); |
| - m_trailingObjects.updateMidpointsForTrailingObjects(m_lineMidpointState, InlineIterator(), TrailingObjects::DoNotCollapseFirstSpace); |
| - } |
| - } |
| - } else if (m_ignoringSpaces) { |
| - // Stop ignoring spaces and begin at this |
| - // new point. |
| - m_ignoringSpaces = false; |
| - lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0; |
| - wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurements.last().width) ? wordSpacing : 0; |
| - lastSpace = m_current.offset(); // e.g., "Foo goo", don't add in any of the ignored spaces. |
| - m_lineMidpointState.stopIgnoringSpaces(InlineIterator(0, m_current.object(), m_current.offset())); |
| - } |
| - |
| - if (isSVGText && m_current.offset()) { |
| - // Force creation of new InlineBoxes for each absolute positioned character (those that start new text chunks). |
| - if (LineLayoutSVGInlineText(layoutText).characterStartsNewTextChunk(m_current.offset())) |
| + // If there is a hard-break available at this whitespace position then take it. |
| + if (c == newlineCharacter && m_preservesNewline) { |
| + if (!stoppedIgnoringSpaces && m_current.offset()) |
| m_lineMidpointState.ensureCharacterGetsLineBox(m_current); |
| + m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition()); |
| + m_lineBreak.increment(); |
| + m_lineInfo.setPreviousLineBrokeCleanly(true); |
| + return true; |
| } |
| - if (prohibitBreakInside) { |
| - m_current.setNextBreakablePosition(layoutText.textLength()); |
| - prohibitBreakInside = false; |
| + // Auto-wrapping text should not wrap in the middle of a word once it has had an |
| + // opportunity to break after a word. |
| + if (m_autoWrap && betweenWords) { |
| + m_width.commit(); |
| + widthFromLastBreakingOpportunity = 0; |
| + m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition()); |
| + breakWords = false; |
| + widthMeasurementAtLastBreakOpportunity = lastWidthMeasurement; |
| } |
| - if (m_currentCharacterIsSpace && !previousCharacterIsSpace) { |
| - m_startOfIgnoredSpaces.setObject(m_current.object()); |
| - m_startOfIgnoredSpaces.setOffset(m_current.offset()); |
| + // Remember this as a breakable position in case adding the end width forces a break. |
| + if (midWordBreak && !U16_IS_TRAIL(c) && !(WTF::Unicode::category(c) & (WTF::Unicode::Mark_NonSpacing | WTF::Unicode::Mark_Enclosing | WTF::Unicode::Mark_SpacingCombining))) { |
| + m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition()); |
| + midWordBreak &= (breakWords || breakAll); |
| } |
| - if (!m_currentCharacterIsSpace && previousCharacterShouldCollapseIfPreWap) { |
| - if (m_autoWrap && m_currentStyle->breakOnlyAfterWhiteSpace()) |
| - m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition()); |
| + if (betweenWords) { |
| + lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0; |
| + wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurement.width) ? wordSpacing : 0; |
| + lastSpace = !breakAll || m_currentCharacterIsSpace ? m_current.offset() : lastSpace; |
| } |
| - if (m_collapseWhiteSpace && m_currentCharacterIsSpace && !m_ignoringSpaces) |
| - m_trailingObjects.setTrailingWhitespace(LineLayoutText(m_current.object())); |
| - else if (!m_currentStyle->collapseWhiteSpace() || !m_currentCharacterIsSpace) |
| - m_trailingObjects.clear(); |
| + // If we encounter a newline, or if we encounter a second space, we need to go ahead and break up this run and enter a mode where we start collapsing spaces. |
| + if (!m_ignoringSpaces && m_currentStyle->collapseWhiteSpace()) { |
| + if (m_currentCharacterIsSpace && previousCharacterIsSpace) { |
| + m_ignoringSpaces = true; |
| + // We just entered a mode where we are ignoring spaces. Create a midpoint to terminate the run before the second space. |
|
kojii
2015/12/08 08:02:10
nit: two spaces between "run" and "before".
|
| + m_lineMidpointState.startIgnoringSpaces(m_startOfIgnoredSpaces); |
| + m_trailingObjects.updateMidpointsForTrailingObjects(m_lineMidpointState, InlineIterator(), TrailingObjects::DoNotCollapseFirstSpace); |
| + } |
| + } |
| + prepareForNextCharacter(layoutText, prohibitBreakInside, previousCharacterIsSpace, previousCharacterShouldCollapseIfPreWap); |
| m_atStart = false; |
| nextCharacter(c, lastCharacter, secondToLastCharacter); |
| } |
| @@ -859,6 +786,120 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool |
| return false; |
| } |
| +inline void BreakingContext::stopIgnoringSpaces(unsigned& lastSpace) |
| +{ |
| + m_ignoringSpaces = false; |
| + lastSpace = m_current.offset(); // e.g., "Foo goo", don't add in any of the ignored spaces. |
| + m_lineMidpointState.stopIgnoringSpaces(InlineIterator(0, m_current.object(), m_current.offset())); |
| +} |
| + |
| +inline WordMeasurement& BreakingContext::calculateWordWidth(WordMeasurements& wordMeasurements, LineLayoutText& layoutText, float lastSpace, float& lastWidthMeasurement, float wordSpacingForWordMeasurement, const Font& font, float wordTrailingSpaceWidth, UChar c) |
|
kojii
2015/12/08 08:02:10
Shouldn't lastSpace be unsigned rather than float?
|
| +{ |
| + wordMeasurements.grow(wordMeasurements.size() + 1); |
| + WordMeasurement& wordMeasurement = wordMeasurements.last(); |
| + wordMeasurement.layoutText = layoutText; |
| + wordMeasurement.endOffset = m_current.offset(); |
| + wordMeasurement.startOffset = lastSpace; |
| + |
| + if (wordTrailingSpaceWidth && c == spaceCharacter) |
| + lastWidthMeasurement = textWidth(layoutText, lastSpace, m_current.offset() + 1 - lastSpace, font, m_width.currentWidth(), m_collapseWhiteSpace, &wordMeasurement.fallbackFonts, &wordMeasurement.glyphBounds) - wordTrailingSpaceWidth; |
| + else |
| + lastWidthMeasurement = textWidth(layoutText, lastSpace, m_current.offset() - lastSpace, font, m_width.currentWidth(), m_collapseWhiteSpace, &wordMeasurement.fallbackFonts, &wordMeasurement.glyphBounds); |
| + |
| + wordMeasurement.width = lastWidthMeasurement + wordSpacingForWordMeasurement; |
| + wordMeasurement.glyphBounds.move(wordSpacingForWordMeasurement, 0); |
| + return wordMeasurement; |
| +} |
| + |
| +inline bool BreakingContext::trailingSpaceExceedsAvailableWidth(bool midWordBreak, const LineLayoutText& layoutText, WordMeasurement& wordMeasurement, bool applyWordSpacing, bool wordSpacing, const Font& font) |
| +{ |
| + // If we break only after white-space, consider the current character |
| + // as candidate width for this line. |
| + if (m_width.fitsOnLine() && m_currentCharacterIsSpace && m_currentStyle->breakOnlyAfterWhiteSpace() && !midWordBreak) { |
| + float charWidth = textWidth(layoutText, m_current.offset(), 1, font, m_width.currentWidth(), m_collapseWhiteSpace, &wordMeasurement.fallbackFonts, &wordMeasurement.glyphBounds) + (applyWordSpacing ? wordSpacing : 0); |
| + // Check if line is too big even without the extra space |
| + // at the end of the line. If it is not, do nothing. |
| + // If the line needs the extra whitespace to be too long, |
| + // then move the line break to the space and skip all |
| + // additional whitespace. |
| + if (!m_width.fitsOnLine(charWidth)) { |
| + m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition()); |
| + skipTrailingWhitespace(m_lineBreak, m_lineInfo); |
| + return true; |
| + } |
| + } |
| + return false; |
| +} |
| + |
| +inline bool BreakingContext::canBreakAtWhitespace(bool breakWords, WordMeasurement& wordMeasurement, bool stoppedIgnoringSpaces, bool& hyphenated, float charWidth, float& hyphenWidth, bool betweenWords, bool midWordBreak, bool breakAll, bool previousCharacterIsSpace, float lastWidthMeasurement, const LineLayoutText& layoutText, const Font& font, bool applyWordSpacing, float wordSpacing) |
| +{ |
| + if (!m_autoWrap && !breakWords) |
| + return false; |
| + |
| + // If we break only after white-space, consider the current character |
| + // as candidate width for this line. |
| + if (trailingSpaceExceedsAvailableWidth(midWordBreak, layoutText, wordMeasurement, applyWordSpacing, wordSpacing, font) || !m_width.fitsOnLine()) { |
| + if (m_lineBreak.atTextParagraphSeparator()) { |
| + if (!stoppedIgnoringSpaces && m_current.offset() > 0) |
| + m_lineMidpointState.ensureCharacterGetsLineBox(m_current); |
| + m_lineBreak.increment(); |
| + m_lineInfo.setPreviousLineBrokeCleanly(true); |
| + wordMeasurement.endOffset = m_lineBreak.offset(); |
| + } |
| + if (m_lineBreak.object() && m_lineBreak.offset() && m_lineBreak.object().isText() && LineLayoutText(m_lineBreak.object()).textLength() && LineLayoutText(m_lineBreak.object()).characterAt(m_lineBreak.offset() - 1) == softHyphenCharacter) |
| + hyphenated = true; |
| + if (m_lineBreak.offset() && m_lineBreak.offset() != (unsigned)wordMeasurement.endOffset && !wordMeasurement.width) { |
| + if (charWidth) { |
| + wordMeasurement.endOffset = m_lineBreak.offset(); |
| + wordMeasurement.width = charWidth; |
| + } |
| + } |
| + // Didn't fit. Jump to the end unless there's still an opportunity to collapse whitespace. |
| + if (m_ignoringSpaces || !m_collapseWhiteSpace || !m_currentCharacterIsSpace || !previousCharacterIsSpace) { |
| + m_atEnd = true; |
| + return true; |
| + } |
| + } else { |
| + if (!betweenWords || (midWordBreak && !m_autoWrap) || (breakAll && !m_currentCharacterIsSpace)) |
| + m_width.addUncommittedWidth(-lastWidthMeasurement); |
| + if (hyphenWidth) { |
| + // Subtract the width of the soft hyphen out since we fit on a line. |
| + m_width.addUncommittedWidth(-hyphenWidth); |
| + hyphenWidth = 0; |
| + } |
| + } |
| + return false; |
| +} |
| + |
| +inline void BreakingContext::prepareForNextCharacter(const LineLayoutText& layoutText, bool& prohibitBreakInside, bool previousCharacterIsSpace, bool previousCharacterShouldCollapseIfPreWap) |
| +{ |
| + if (layoutText.isSVGInlineText() && m_current.offset()) { |
| + // Force creation of new InlineBoxes for each absolute positioned character (those that start new text chunks). |
| + if (LineLayoutSVGInlineText(layoutText).characterStartsNewTextChunk(m_current.offset())) |
| + m_lineMidpointState.ensureCharacterGetsLineBox(m_current); |
| + } |
| + |
| + if (prohibitBreakInside) { |
| + m_current.setNextBreakablePosition(layoutText.textLength()); |
| + prohibitBreakInside = false; |
| + } |
| + |
| + if (m_currentCharacterIsSpace && !previousCharacterIsSpace) { |
| + m_startOfIgnoredSpaces.setObject(m_current.object()); |
| + m_startOfIgnoredSpaces.setOffset(m_current.offset()); |
| + } |
| + |
| + if (!m_currentCharacterIsSpace && previousCharacterShouldCollapseIfPreWap) { |
| + if (m_autoWrap && m_currentStyle->breakOnlyAfterWhiteSpace()) |
| + m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition()); |
| + } |
| + |
| + if (m_collapseWhiteSpace && m_currentCharacterIsSpace && !m_ignoringSpaces) |
| + m_trailingObjects.setTrailingWhitespace(LineLayoutText(m_current.object())); |
| + else if (!m_currentStyle->collapseWhiteSpace() || !m_currentCharacterIsSpace) |
| + m_trailingObjects.clear(); |
| +} |
| + |
| inline void BreakingContext::commitAndUpdateLineBreakIfNeeded() |
| { |
| bool checkForBreak = m_autoWrap; |