public void finishBreaksOptimal() { // clear existing greedy break result mBreaks.clear(); mWidths.clear(); mFlags.clear(); int nCand = mCandidates.size(); int prev = new int(); for (int i = nCand - 1; i > 0; i = prev) { prev = mCandidates[i].prev; mBreaks.push_back(mCandidates[i].offset); mWidths.push_back(mCandidates[i].postBreak - mCandidates[prev].preBreak); int flags = HyphenEdit.editForThisLine(mCandidates[i].hyphenType); if (prev > 0) { flags |= HyphenEdit.editForNextLine(mCandidates[prev].hyphenType); } mFlags.push_back(flags); } std::reverse(mBreaks.begin(), mBreaks.end()); std::reverse(mWidths.begin(), mWidths.end()); std::reverse(mFlags.begin(), mFlags.end()); }
public void pushGreedyBreak() { Candidate bestCandidate = mCandidates[mBestBreak]; pushBreak(bestCandidate.offset, bestCandidate.postBreak - mPreBreak, mLastHyphenation | HyphenEdit.editForThisLine(bestCandidate.hyphenType)); mBestScore = SCORE_INFTY; #if VERBOSE_DEBUG ALOGD("break: %d %g", mBreaks.back(), mWidths.back()); #endif mLastBreak = mBestBreak; mPreBreak = bestCandidate.preBreak; mLastHyphenation = HyphenEdit.editForNextLine(bestCandidate.hyphenType); }
// TODO: this class is actually fairly close to being general and not tied to // using Minikin to do the shaping of the strings. The main thing that would // need to be changed is having some kind of callback (or virtual class, or // maybe even template), which could easily be instantiated with Minikin's // Layout. Future work for when needed. public float addStyleRun(MinikinPaint paint, FontCollection typeface, FontStyle style, int start, int end, bool isRtl) { float width = 0.0f; int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; float hyphenPenalty = 0.0F; if (paint != null) { width = Layout.measureText(mTextBuf.data(), start, end - start, mTextBuf.size(), bidiFlags, style, paint, typeface, mCharWidths.data() + start); // a heuristic that seems to perform well hyphenPenalty = 0.5 * paint.size * paint.scaleX * mLineWidths.getLineWidth(0); if (mHyphenationFrequency == kHyphenationFrequency_Normal) { hyphenPenalty *= 4.0; // TODO: Replace with a better value after some testing } if (mJustified) { // Make hyphenation more aggressive for fully justified text (so that // "normal" in justified mode is the same as "full" in ragged-right). hyphenPenalty *= 0.25; } else { // Line penalty is zero for justified text. mLinePenalty = Math.Max(mLinePenalty, hyphenPenalty * LINE_PENALTY_MULTIPLIER); } } int current = (int)mWordBreaker.current(); int afterWord = start; int lastBreak = start; ParaWidth lastBreakWidth = mWidth; ParaWidth postBreak = mWidth; int postSpaceCount = mSpaceCount; for (int i = start; i < end; i++) { UInt16 c = mTextBuf[i]; if (c == CHAR_TAB) { mWidth = mPreBreak + mTabStops.nextTab(mWidth - mPreBreak); if (mFirstTabIndex == INT_MAX) { mFirstTabIndex = (int)i; } // fall back to greedy; other modes don't know how to deal with tabs mStrategy = kBreakStrategy_Greedy; } else { if (isWordSpace(new UInt16(c))) { mSpaceCount += 1; } mWidth += mCharWidths[i]; if (!isLineEndSpace(new UInt16(c))) { postBreak = mWidth; postSpaceCount = mSpaceCount; //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created: //ORIGINAL LINE: afterWord = i + 1; afterWord.CopyFrom(i + 1); } } if (i + 1 == current != null) { int wordStart = mWordBreaker.wordStart(); int wordEnd = mWordBreaker.wordEnd(); if (paint != null && mHyphenator != null && mHyphenationFrequency != kHyphenationFrequency_None && wordStart >= start != null && wordEnd > wordStart && wordEnd - wordStart <= LONGEST_HYPHENATED_WORD) { mHyphenator.hyphenate(mHyphBuf, mTextBuf[wordStart], wordEnd - wordStart, mLocale); #if VERBOSE_DEBUG string hyphenatedString; for (int j = wordStart; j < wordEnd; j++) { if (mHyphBuf[j - wordStart] == HyphenationType.BREAK_AND_INSERT_HYPHEN) { hyphenatedString.push_back('-'); } // Note: only works with ASCII, should do UTF-8 conversion here hyphenatedString.push_back(buffer()[j]); } ALOGD("hyphenated string: %s", hyphenatedString); #endif // measure hyphenated substrings for (int j = wordStart; j < wordEnd; j++) { HyphenationType hyph = mHyphBuf[j - wordStart]; if (hyph != HyphenationType.DONT_BREAK) { paint.hyphenEdit = HyphenEdit.editForThisLine(hyph); float firstPartWidth = Layout.measureText(mTextBuf.data(), lastBreak, j - lastBreak, mTextBuf.size(), bidiFlags, style, paint, typeface, null); ParaWidth hyphPostBreak = lastBreakWidth + firstPartWidth; paint.hyphenEdit = HyphenEdit.editForNextLine(hyph); float secondPartWidth = Layout.measureText(mTextBuf.data(), j, afterWord - j, mTextBuf.size(), bidiFlags, style, paint, typeface, null); ParaWidth hyphPreBreak = postBreak - secondPartWidth; addWordBreak(j, hyphPreBreak, hyphPostBreak, postSpaceCount, postSpaceCount, hyphenPenalty, hyph); paint.hyphenEdit = HyphenEdit.NO_EDIT; } } } // Skip break for zero-width characters inside replacement span if (paint != null || current == end || mCharWidths[current] > 0) { float penalty = hyphenPenalty * mWordBreaker.breakBadness(); addWordBreak(current, mWidth, postBreak, mSpaceCount, postSpaceCount, penalty, HyphenationType.DONT_BREAK); } //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created: //ORIGINAL LINE: lastBreak = current; lastBreak.CopyFrom(current); lastBreakWidth = mWidth; //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created: //ORIGINAL LINE: current = (int)mWordBreaker.next(); current.CopyFrom((int)mWordBreaker.next()); } } return(width); }