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

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

Issue 1978683002: Enable hyphens: auto and none in BreakingContext (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add comments for heuristic, adjust widths of hyphens-auto-mock test Created 4 years, 7 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/WebKit/Source/core/core.gypi ('k') | third_party/WebKit/Source/core/testing/Internals.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 7b5d2a0a98770914df9efc22daa3aa66bbd6a2a1..0f1954b5ea054a974c33bf9f3b128cabb193cf4d 100644
--- a/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h
+++ b/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h
@@ -40,6 +40,8 @@
#include "core/layout/line/TrailingObjects.h"
#include "core/layout/line/WordMeasurement.h"
#include "core/paint/PaintLayer.h"
+#include "platform/fonts/CharacterRange.h"
+#include "platform/text/Hyphenation.h"
#include "platform/text/TextBreakIterator.h"
#include "wtf/Allocator.h"
#include "wtf/Vector.h"
@@ -99,7 +101,7 @@ public:
void handleReplaced();
bool handleText(WordMeasurements&, bool& hyphenated);
void prepareForNextCharacter(const LineLayoutText&, bool& prohibitBreakInside, bool previousCharacterIsSpace);
- bool canBreakAtWhitespace(bool breakWords, WordMeasurement&, bool stoppedIgnoringSpaces, bool& hyphenated, float charWidth, float& hyphenWidth, bool betweenWords, bool midWordBreak, bool canBreakMidWord, bool previousCharacterIsSpace, float lastWidthMeasurement, const LineLayoutText&, const Font&, bool applyWordSpacing, float wordSpacing);
+ bool canBreakAtWhitespace(bool breakWords, WordMeasurement&, bool stoppedIgnoringSpaces, float charWidth, bool& hyphenated, bool disableSoftHyphen, float& hyphenWidth, bool betweenWords, bool midWordBreak, bool canBreakMidWord, bool previousCharacterIsSpace, float lastWidthMeasurement, const LineLayoutText&, const Font&, bool applyWordSpacing, float wordSpacing);
bool trailingSpaceExceedsAvailableWidth(bool canBreakMidWord, const LineLayoutText&, WordMeasurement&, bool applyWordSpacing, bool wordSpacing, const Font&);
WordMeasurement& calculateWordWidth(WordMeasurements&, LineLayoutText&, unsigned lastSpace, float& lastWidthMeasurement, float wordSpacingForWordMeasurement, const Font&, float wordTrailingSpaceWidth, UChar);
void stopIgnoringSpaces(unsigned& lastSpace);
@@ -117,6 +119,7 @@ private:
bool rewindToMidWordBreak(WordMeasurement&, int end, float width);
bool rewindToFirstMidWordBreak(LineLayoutText, const ComputedStyle&, const Font&, bool breakAll, WordMeasurement&);
bool rewindToMidWordBreak(LineLayoutText, const ComputedStyle&, const Font&, bool breakAll, WordMeasurement&);
+ bool hyphenate(LineLayoutText, const ComputedStyle&, const Font&, const Hyphenation&, float lastSpaceWordSpacing, WordMeasurement&);
InlineBidiResolver& m_resolver;
@@ -560,8 +563,8 @@ ALWAYS_INLINE bool BreakingContext::rewindToMidWordBreak(
wordMeasurement.endOffset = end;
wordMeasurement.width = width;
- m_current.moveTo(m_current.getLineLayoutItem(), end);
- m_lineBreak.moveTo(m_current.getLineLayoutItem(), m_current.offset());
+ m_current.moveTo(m_current.getLineLayoutItem(), end, m_current.nextBreakablePosition());
+ m_lineBreak.moveTo(m_current.getLineLayoutItem(), end, m_current.nextBreakablePosition());
return true;
}
@@ -622,6 +625,47 @@ ALWAYS_INLINE bool BreakingContext::rewindToMidWordBreak(LineLayoutText text,
return rewindToMidWordBreak(wordMeasurement, end, rect.width());
}
+ALWAYS_INLINE bool BreakingContext::hyphenate(LineLayoutText text,
+ const ComputedStyle& style, const Font& font,
+ const Hyphenation& hyphenation, float lastSpaceWordSpacing,
+ WordMeasurement& wordMeasurement)
+{
+ const unsigned minimumPrefixLength = 2;
+ const unsigned minimumSuffixLength = 2;
+ unsigned start = wordMeasurement.startOffset;
+ unsigned len = wordMeasurement.endOffset - start;
+ if (len <= minimumSuffixLength)
+ return false;
+
+ float hyphenWidth = text.hyphenWidth(font, textDirectionFromUnicode(m_resolver.position().direction()));
+ float maxPrefixWidth = m_width.availableWidth()
+ - m_width.currentWidth() - hyphenWidth - lastSpaceWordSpacing;
+
+ // If the maximum width available for the prefix before the hyphen is small, then it is very unlikely
+ // that an hyphenation opportunity exists, so do not bother to look for it.
+ // These are heuristic numbers for performance added in http://wkb.ug/45606 .
+ const int minPrefixWidthNumerator = 5;
+ const int minPrefixWidthDenominator = 4;
+ if (maxPrefixWidth <= font.getFontDescription().computedSize() * minPrefixWidthNumerator / minPrefixWidthDenominator)
+ return false;
+
+ TextRun run = constructTextRun(font, text, start, len, style);
+ run.setTabSize(!m_collapseWhiteSpace, style.getTabSize());
+ run.setXPos(m_width.currentWidth());
+ unsigned maxPrefixLength = font.offsetForPosition(run, maxPrefixWidth, false);
+ if (maxPrefixLength < minimumPrefixLength)
+ return false;
+
+ unsigned prefixLength = hyphenation.lastHyphenLocation(
+ text.text().createView(start, len),
+ std::min(maxPrefixLength, len - minimumSuffixLength) + 1);
+ if (!prefixLength || prefixLength < minimumPrefixLength)
+ return false;
+
+ CharacterRange range = font.getCharacterRange(run, 0, prefixLength);
+ return rewindToMidWordBreak(wordMeasurement, start + prefixLength, range.width());
+}
+
inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool& hyphenated)
{
if (!m_current.offset())
@@ -660,6 +704,9 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
// See: fast/css3-text/css3-word-break/word-break-all-wrap-with-floats.html
float widthMeasurementAtLastBreakOpportunity = 0;
+ Hyphenation* hyphenation = style.getHyphens() == HyphensAuto
+ ? Hyphenation::get(font.getFontDescription().locale()) : nullptr;
+ bool disableSoftHyphen = style.getHyphens() == HyphensNone;
float hyphenWidth = 0;
if (layoutText.isSVGInlineText()) {
@@ -705,7 +752,7 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
m_width.setTrailingWhitespaceWidth(0);
}
- if (c == softHyphenCharacter && m_autoWrap && !hyphenWidth) {
+ if (c == softHyphenCharacter && m_autoWrap && !hyphenWidth && !disableSoftHyphen) {
hyphenWidth = layoutText.hyphenWidth(font, textDirectionFromUnicode(m_resolver.position().direction()));
m_width.addUncommittedWidth(hyphenWidth);
}
@@ -726,7 +773,8 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
// 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, lineBreakType));
+ bool betweenWords = c == newlineCharacter || (m_currWS != PRE && !m_atStart && m_layoutTextInfo.m_lineBreakIterator.isBreakable(m_current.offset(), nextBreakablePosition, lineBreakType)
+ && (!disableSoftHyphen || m_current.previousInSameNode() != softHyphenCharacter));
m_current.setNextBreakablePosition(nextBreakablePosition);
// 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.
@@ -788,18 +836,31 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
m_width.fitBelowFloats(m_lineInfo.isFirstLine());
midWordBreak = false;
- if (canBreakMidWord && !m_width.fitsOnLine()) {
- m_width.addUncommittedWidth(-wordMeasurement.width);
- if (rewindToMidWordBreak(layoutText, style, font, breakAll, wordMeasurement)) {
- lastWidthMeasurement = wordMeasurement.width + lastSpaceWordSpacing;
- midWordBreak = true;
+ if (!m_width.fitsOnLine()) {
+ if (canBreakMidWord) {
+ m_width.addUncommittedWidth(-wordMeasurement.width);
+ if (rewindToMidWordBreak(layoutText, style, font, breakAll, wordMeasurement)) {
+ lastWidthMeasurement = wordMeasurement.width + lastSpaceWordSpacing;
+ midWordBreak = true;
+ }
+ m_width.addUncommittedWidth(wordMeasurement.width);
+ } else if (hyphenation) {
+ m_width.addUncommittedWidth(-wordMeasurement.width);
+ DCHECK(lastSpace == static_cast<unsigned>(wordMeasurement.startOffset));
+ DCHECK(m_current.offset() == static_cast<unsigned>(wordMeasurement.endOffset));
+ if (hyphenate(layoutText, style, font, *hyphenation, lastSpaceWordSpacing, wordMeasurement)) {
+ m_width.addUncommittedWidth(wordMeasurement.width);
+ hyphenated = true;
+ m_atEnd = true;
+ return false;
+ }
+ m_width.addUncommittedWidth(wordMeasurement.width);
}
- m_width.addUncommittedWidth(wordMeasurement.width);
}
// 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, canBreakMidWord, previousCharacterIsSpace, lastWidthMeasurement, layoutText, font, applyWordSpacing, wordSpacing))
+ if (canBreakAtWhitespace(breakWords, wordMeasurement, stoppedIgnoringSpaces, charWidth, hyphenated, disableSoftHyphen, hyphenWidth, betweenWords, midWordBreak, canBreakMidWord, previousCharacterIsSpace, lastWidthMeasurement, layoutText, font, applyWordSpacing, wordSpacing))
return false;
// If there is a hard-break available at this whitespace position then take it.
@@ -882,10 +943,23 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
if (midWordBreak) {
m_width.commit();
m_atEnd = true;
- } else if (!m_width.fitsOnLine() && !hyphenated
- && m_lineBreak.previousInSameNode() == softHyphenCharacter) {
- hyphenated = true;
- m_atEnd = true;
+ } else if (!m_width.fitsOnLine()) {
+ if (hyphenation && (m_nextObject || m_lineInfo.isEmpty())) {
+ m_width.addUncommittedWidth(-wordMeasurement.width);
+ DCHECK(lastSpace == static_cast<unsigned>(wordMeasurement.startOffset));
+ DCHECK(m_current.offset() == static_cast<unsigned>(wordMeasurement.endOffset));
+ if (hyphenate(layoutText, style, font, *hyphenation, lastSpaceWordSpacing, wordMeasurement)) {
+ hyphenated = true;
+ m_atEnd = true;
+ }
+ m_width.addUncommittedWidth(wordMeasurement.width);
+ }
+ if (!hyphenated
+ && m_lineBreak.previousInSameNode() == softHyphenCharacter
+ && !disableSoftHyphen) {
+ hyphenated = true;
+ m_atEnd = true;
+ }
}
return false;
}
@@ -961,7 +1035,7 @@ inline bool BreakingContext::trailingSpaceExceedsAvailableWidth(bool canBreakMid
return false;
}
-inline bool BreakingContext::canBreakAtWhitespace(bool breakWords, WordMeasurement& wordMeasurement, bool stoppedIgnoringSpaces, bool& hyphenated, float charWidth, float& hyphenWidth, bool betweenWords, bool midWordBreak, bool canBreakMidWord, bool previousCharacterIsSpace, float lastWidthMeasurement, const LineLayoutText& layoutText, const Font& font, bool applyWordSpacing, float wordSpacing)
+inline bool BreakingContext::canBreakAtWhitespace(bool breakWords, WordMeasurement& wordMeasurement, bool stoppedIgnoringSpaces, float charWidth, bool& hyphenated, bool disableSoftHyphen, float& hyphenWidth, bool betweenWords, bool midWordBreak, bool canBreakMidWord, bool previousCharacterIsSpace, float lastWidthMeasurement, const LineLayoutText& layoutText, const Font& font, bool applyWordSpacing, float wordSpacing)
{
if (!m_autoWrap && !breakWords)
return false;
@@ -978,7 +1052,7 @@ inline bool BreakingContext::canBreakAtWhitespace(bool breakWords, WordMeasureme
m_lineInfo.setPreviousLineBrokeCleanly(true);
wordMeasurement.endOffset = m_lineBreak.offset();
}
- if (m_lineBreak.getLineLayoutItem() && m_lineBreak.offset() && m_lineBreak.getLineLayoutItem().isText() && LineLayoutText(m_lineBreak.getLineLayoutItem()).textLength() && LineLayoutText(m_lineBreak.getLineLayoutItem()).characterAt(m_lineBreak.offset() - 1) == softHyphenCharacter)
+ if (m_lineBreak.getLineLayoutItem() && m_lineBreak.offset() && m_lineBreak.getLineLayoutItem().isText() && LineLayoutText(m_lineBreak.getLineLayoutItem()).textLength() && LineLayoutText(m_lineBreak.getLineLayoutItem()).characterAt(m_lineBreak.offset() - 1) == softHyphenCharacter && !disableSoftHyphen)
hyphenated = true;
if (m_lineBreak.offset() && m_lineBreak.offset() != (unsigned)wordMeasurement.endOffset && !wordMeasurement.width) {
if (charWidth) {
« no previous file with comments | « third_party/WebKit/Source/core/core.gypi ('k') | third_party/WebKit/Source/core/testing/Internals.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698