summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libs/minikin/Layout.cpp49
-rw-r--r--libs/minikin/LineBreaker.cpp12
-rw-r--r--libs/minikin/Measurement.cpp3
3 files changed, 51 insertions, 13 deletions
diff --git a/libs/minikin/Layout.cpp b/libs/minikin/Layout.cpp
index 17ce596..bac5fc7 100644
--- a/libs/minikin/Layout.cpp
+++ b/libs/minikin/Layout.cpp
@@ -514,6 +514,29 @@ static size_t getNextWordBreak(const uint16_t* chars, size_t offset, size_t len)
return len;
}
+/**
+ * Disable certain scripts (mostly those with cursive connection) from having letterspacing
+ * applied. See https://github.com/behdad/harfbuzz/issues/64 for more details.
+ */
+static bool isScriptOkForLetterspacing(hb_script_t script) {
+ return !(
+ script == HB_SCRIPT_ARABIC ||
+ script == HB_SCRIPT_NKO ||
+ script == HB_SCRIPT_PSALTER_PAHLAVI ||
+ script == HB_SCRIPT_MANDAIC ||
+ script == HB_SCRIPT_MONGOLIAN ||
+ script == HB_SCRIPT_PHAGS_PA ||
+ script == HB_SCRIPT_DEVANAGARI ||
+ script == HB_SCRIPT_BENGALI ||
+ script == HB_SCRIPT_GURMUKHI ||
+ script == HB_SCRIPT_MODI ||
+ script == HB_SCRIPT_SHARADA ||
+ script == HB_SCRIPT_SYLOTI_NAGRI ||
+ script == HB_SCRIPT_TIRHUTA ||
+ script == HB_SCRIPT_OGHAM
+ );
+}
+
void Layout::doLayout(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
int bidiFlags, const FontStyle &style, const MinikinPaint &paint) {
AutoMutex _l(gMinikinLock);
@@ -678,15 +701,6 @@ void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t
double size = ctx->paint.size;
double scaleX = ctx->paint.scaleX;
- double letterSpace = ctx->paint.letterSpacing * size * scaleX;
- double letterSpaceHalfLeft;
- if ((ctx->paint.paintFlags & LinearTextFlag) == 0) {
- letterSpace = round(letterSpace);
- letterSpaceHalfLeft = floor(letterSpace * 0.5);
- } else {
- letterSpaceHalfLeft = letterSpace * 0.5;
- }
- double letterSpaceHalfRight = letterSpace - letterSpaceHalfLeft;
float x = mAdvance;
float y = 0;
@@ -716,6 +730,21 @@ void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t
srunend = srunstart;
hb_script_t script = getScriptRun(buf + start, run.end, &srunend);
+ double letterSpace = 0.0;
+ double letterSpaceHalfLeft = 0.0;
+ double letterSpaceHalfRight = 0.0;
+
+ if (ctx->paint.letterSpacing != 0.0 && isScriptOkForLetterspacing(script)) {
+ letterSpace = ctx->paint.letterSpacing * size * scaleX;
+ if ((ctx->paint.paintFlags & LinearTextFlag) == 0) {
+ letterSpace = round(letterSpace);
+ letterSpaceHalfLeft = floor(letterSpace * 0.5);
+ } else {
+ letterSpaceHalfLeft = letterSpace * 0.5;
+ }
+ letterSpaceHalfRight = letterSpace - letterSpaceHalfLeft;
+ }
+
hb_buffer_clear_contents(buffer);
hb_buffer_set_script(buffer, script);
hb_buffer_set_direction(buffer, isRtl? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
@@ -728,7 +757,7 @@ void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t
if (ctx->paint.hyphenEdit.hasHyphen() && srunend > srunstart) {
// TODO: check whether this is really the desired semantics. It could have the
// effect of assigning the hyphen width to a nonspacing mark
- unsigned int lastCluster = srunend - 1;
+ unsigned int lastCluster = start + srunend - 1;
hb_codepoint_t hyphenChar = 0x2010; // HYPHEN
hb_codepoint_t glyph;
diff --git a/libs/minikin/LineBreaker.cpp b/libs/minikin/LineBreaker.cpp
index 8275a6c..baf2dfa 100644
--- a/libs/minikin/LineBreaker.cpp
+++ b/libs/minikin/LineBreaker.cpp
@@ -353,12 +353,17 @@ void LineBreaker::computeBreaksOptimal(bool isRectangle) {
float delta = mCandidates[j].preBreak - leftEdge;
// compute width score for line
+
+ // Note: the "bestHope" optimization makes the assumption that, when delta is
+ // non-negative, widthScore will increase monotonically as successive candidate
+ // breaks are considered.
float widthScore = 0.0f;
+ float additionalPenalty = 0.0f;
if (delta < 0) {
widthScore = SCORE_OVERFULL;
} else if (atEnd && mStrategy != kBreakStrategy_Balanced) {
// increase penalty for hyphen on last line
- widthScore = LAST_LINE_PENALTY_MULTIPLIER * mCandidates[j].penalty;
+ additionalPenalty = LAST_LINE_PENALTY_MULTIPLIER * mCandidates[j].penalty;
} else {
widthScore = delta * delta;
}
@@ -369,7 +374,7 @@ void LineBreaker::computeBreaksOptimal(bool isRectangle) {
bestHope = widthScore;
}
- float score = jScore + widthScore;
+ float score = jScore + widthScore + additionalPenalty;
if (score <= best) {
best = score;
bestPrev = j;
@@ -378,6 +383,9 @@ void LineBreaker::computeBreaksOptimal(bool isRectangle) {
mCandidates[i].score = best + mCandidates[i].penalty + mLinePenalty;
mCandidates[i].prev = bestPrev;
mCandidates[i].lineNumber = mCandidates[bestPrev].lineNumber + 1;
+#if VERBOSE_DEBUG
+ ALOGD("break %d: score=%g, prev=%d", i, mCandidates[i].score, mCandidates[i].prev);
+#endif
}
finishBreaksOptimal();
}
diff --git a/libs/minikin/Measurement.cpp b/libs/minikin/Measurement.cpp
index 0b68ac5..a7bc64b 100644
--- a/libs/minikin/Measurement.cpp
+++ b/libs/minikin/Measurement.cpp
@@ -41,7 +41,8 @@ static float getRunAdvance(Layout& layout, const uint16_t* buf, size_t layoutSta
clusterWidth = charAdvance;
}
}
- if (offset < start + count && layout.getCharAdvance(offset - layoutStart) == 0.0f) {
+ if (offset < start + count && layout.getCharAdvance(offset - layoutStart) == 0.0f &&
+ !GraphemeBreak::isGraphemeBreak(buf, start, count, offset)) {
// In the middle of a cluster, distribute width of cluster so that each grapheme cluster
// gets an equal share.
// TODO: get caret information out of font when that's available