From baf6d0a41fdabb0f859bd065f3724921a3e91089 Mon Sep 17 00:00:00 2001 From: Roozbeh Pournader Date: Tue, 14 Jul 2015 13:04:49 -0700 Subject: Avoid re-hyphenating already-hyphenated phrases. Previously, automatic hyphenation blindly took almost every line breaking opportunity as a word break, so words like "low-budget" were treated as two separate words, "low-", and "budget", each automatically hyphenated. This patch makes sure the subwords in already-hyphenated phrases are not passed to the automatic hyphenator, while keeping the possibility of a potential line break where a hyphen already exists. Bug: 22484266 Bug: 22287425 Change-Id: Ie46dbdd70e993d64a9b9cf44b4ae93b21459dbc2 --- libs/minikin/LineBreaker.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libs/minikin/LineBreaker.cpp b/libs/minikin/LineBreaker.cpp index baf2dfa..bf8be26 100644 --- a/libs/minikin/LineBreaker.cpp +++ b/libs/minikin/LineBreaker.cpp @@ -29,7 +29,9 @@ using std::vector; namespace android { const int CHAR_TAB = 0x0009; +const uint16_t CHAR_HYPHEN_MINUS = 0x002D; const uint16_t CHAR_SOFT_HYPHEN = 0x00AD; +const uint16_t CHAR_HYPHEN = 0x2010; // Large scores in a hierarchy; we prefer desperate breaks to an overfull line. All these // constants are larger than any reasonable actual width score. @@ -138,6 +140,7 @@ float LineBreaker::addStyleRun(MinikinPaint* paint, const FontCollection* typefa size_t lastBreak = start; ParaWidth lastBreakWidth = mWidth; ParaWidth postBreak = mWidth; + bool temporarilySkipHyphenation = false; for (size_t i = start; i < end; i++) { uint16_t c = mTextBuf[i]; if (c == CHAR_TAB) { @@ -158,8 +161,12 @@ float LineBreaker::addStyleRun(MinikinPaint* paint, const FontCollection* typefa // Override ICU's treatment of soft hyphen as a break opportunity, because we want it // to be a hyphen break, with penalty and drawing behavior. if (c != CHAR_SOFT_HYPHEN) { + // TODO: Add a new type of HyphenEdit for breaks whose hyphen already exists, so + // we can pass the whole word down to Hyphenator like the soft hyphen case. + bool wordEndsInHyphen = (c == CHAR_HYPHEN_MINUS || c == CHAR_HYPHEN); if (paint != nullptr && mHyphenator != nullptr && mHyphenationFrequency != kHyphenationFrequency_None && + !wordEndsInHyphen && !temporarilySkipHyphenation && wordEnd > lastBreak && wordEnd - lastBreak <= LONGEST_HYPHENATED_WORD) { mHyphenator->hyphenate(&mHyphBuf, &mTextBuf[lastBreak], wordEnd - lastBreak); #if VERBOSE_DEBUG @@ -188,6 +195,8 @@ float LineBreaker::addStyleRun(MinikinPaint* paint, const FontCollection* typefa } } } + // Skip hyphenating the next word if and only if the present word ends in a hyphen + temporarilySkipHyphenation = wordEndsInHyphen; // Skip break for zero-width characters. if (current == mTextBuf.size() || mCharWidths[current] > 0) { -- cgit v1.2.3