summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBehdad Esfahbod <behdad@google.com>2014-07-17 19:47:01 -0400
committerBehdad Esfahbod <behdad@google.com>2014-07-22 16:37:53 -0400
commit8e7a3dae37e9a22b2c054aec852615843d71caf6 (patch)
treeaffb3b03d6a5c703b0b6f94d793f54abbdb38d0c
parent4422f4dd941628ad289bcabc75fbd788d37415f6 (diff)
downloadandroid_frameworks_minikin-8e7a3dae37e9a22b2c054aec852615843d71caf6.tar.gz
android_frameworks_minikin-8e7a3dae37e9a22b2c054aec852615843d71caf6.tar.bz2
android_frameworks_minikin-8e7a3dae37e9a22b2c054aec852615843d71caf6.zip
Add letter-spacing support
Bug: 15594400 Change-Id: Ied94d7674be4097b0f44c9b0770d3294dc6433c1
-rw-r--r--include/minikin/CssParse.h2
-rw-r--r--include/minikin/MinikinFont.h1
-rw-r--r--libs/minikin/CssParse.cpp1
-rw-r--r--libs/minikin/Layout.cpp45
4 files changed, 45 insertions, 4 deletions
diff --git a/include/minikin/CssParse.h b/include/minikin/CssParse.h
index ea28b81..259b933 100644
--- a/include/minikin/CssParse.h
+++ b/include/minikin/CssParse.h
@@ -30,6 +30,7 @@ enum CssTag {
fontStyle,
fontWeight,
cssLang,
+ letterSpacing,
minikinBidi,
minikinHinting,
minikinVariant,
@@ -44,6 +45,7 @@ const std::string cssTagNames[] = {
"font-style",
"font-weight",
"lang",
+ "letter-spacing",
"-minikin-bidi",
"-minikin-hinting",
"-minikin-variant",
diff --git a/include/minikin/MinikinFont.h b/include/minikin/MinikinFont.h
index 7915ef2..935d4bb 100644
--- a/include/minikin/MinikinFont.h
+++ b/include/minikin/MinikinFont.h
@@ -34,6 +34,7 @@ struct MinikinPaint {
float size;
float scaleX;
float skewX;
+ float letterSpacing;
uint32_t paintFlags;
FontFakery fakery;
};
diff --git a/libs/minikin/CssParse.cpp b/libs/minikin/CssParse.cpp
index 8168a74..057dab7 100644
--- a/libs/minikin/CssParse.cpp
+++ b/libs/minikin/CssParse.cpp
@@ -44,6 +44,7 @@ static CssTag parseTag(const string str, size_t off, size_t len) {
if (strEqC(str, off, len, "font-style")) return fontStyle;
} else if (c == 'l') {
if (strEqC(str, off, len, "lang")) return cssLang;
+ if (strEqC(str, off, len, "letter-spacing")) return letterSpacing;
} else if (c == '-') {
if (strEqC(str, off, len, "-minikin-bidi")) return minikinBidi;
if (strEqC(str, off, len, "-minikin-hinting")) return minikinHinting;
diff --git a/libs/minikin/Layout.cpp b/libs/minikin/Layout.cpp
index 21b8362..5125a32 100644
--- a/libs/minikin/Layout.cpp
+++ b/libs/minikin/Layout.cpp
@@ -64,6 +64,7 @@ public:
const uint16_t* chars, size_t start, size_t count, size_t nchars, bool dir)
: mStart(start), mCount(count), mId(collection->getId()), mStyle(style),
mSize(paint.size), mScaleX(paint.scaleX), mSkewX(paint.skewX),
+ mLetterSpacing(paint.letterSpacing),
mPaintFlags(paint.paintFlags), mIsRtl(dir) {
mText.setTo(chars, nchars);
}
@@ -81,6 +82,7 @@ private:
float mSize;
float mScaleX;
float mSkewX;
+ float mLetterSpacing;
int32_t mPaintFlags;
bool mIsRtl;
// Note: any fields added to MinikinPaint must also be reflected here.
@@ -144,6 +146,7 @@ bool LayoutCacheKey::operator==(const LayoutCacheKey& other) const {
&& mSize == other.mSize
&& mScaleX == other.mScaleX
&& mSkewX == other.mSkewX
+ && mLetterSpacing == other.mLetterSpacing
&& mPaintFlags == other.mPaintFlags
&& mIsRtl == other.mIsRtl
&& mText == other.mText;
@@ -157,6 +160,7 @@ hash_t LayoutCacheKey::hash() const {
hash = JenkinsHashMix(hash, hash_type(mSize));
hash = JenkinsHashMix(hash, hash_type(mScaleX));
hash = JenkinsHashMix(hash, hash_type(mSkewX));
+ hash = JenkinsHashMix(hash, hash_type(mLetterSpacing));
hash = JenkinsHashMix(hash, hash_type(mPaintFlags));
hash = JenkinsHashMix(hash, hash_type(mIsRtl));
hash = JenkinsHashMixShorts(hash, mText.string(), mText.size());
@@ -511,6 +515,8 @@ void Layout::doLayout(const uint16_t* buf, size_t start, size_t count, size_t bu
? ctx.props.value(fontScaleX).getDoubleValue() : 1;
ctx.paint.skewX = ctx.props.hasTag(fontSkewX)
? ctx.props.value(fontSkewX).getDoubleValue() : 0;
+ ctx.paint.letterSpacing = ctx.props.hasTag(letterSpacing)
+ ? ctx.props.value(letterSpacing).getDoubleValue() : 0;
ctx.paint.paintFlags = ctx.props.hasTag(paintFlags)
? ctx.props.value(paintFlags).getUintValue() : 0;
int bidiFlags = ctx.props.hasTag(minikinBidi) ? ctx.props.value(minikinBidi).getIntValue() : 0;
@@ -646,8 +652,25 @@ void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t
}
vector<hb_feature_t> features;
+ // Disable default-on non-required ligature features if letter-spacing
+ // See http://dev.w3.org/csswg/css-text-3/#letter-spacing-property
+ // "When the effective spacing between two characters is not zero (due to
+ // either justification or a non-zero value of letter-spacing), user agents
+ // should not apply optional ligatures."
+ if (fabs(ctx->paint.letterSpacing) > 0.03)
+ {
+ static const hb_feature_t no_liga = { HB_TAG('l', 'i', 'g', 'a'), 0, 0, ~0u };
+ static const hb_feature_t no_clig = { HB_TAG('c', 'l', 'i', 'g'), 0, 0, ~0u };
+ features.push_back(no_liga);
+ features.push_back(no_clig);
+ }
addFeatures(&features);
+ double size = ctx->paint.size;
+ double scaleX = ctx->paint.scaleX;
+ double letterSpace = ctx->paint.letterSpacing * size * scaleX;
+ double letterSpaceHalf = letterSpace * .5;
+
float x = mAdvance;
float y = 0;
for (size_t run_ix = 0; run_ix < items.size(); run_ix++) {
@@ -664,8 +687,7 @@ void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t
std::cout << "Run " << run_ix << ", font " << font_ix <<
" [" << run.start << ":" << run.end << "]" << std::endl;
#endif
- double size = ctx->paint.size;
- double scaleX = ctx->paint.scaleX;
+
hb_font_set_ppem(hbFont, size * scaleX, size);
hb_font_set_scale(hbFont, HBFloatToFixed(size * scaleX), HBFloatToFixed(size));
@@ -689,11 +711,22 @@ void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t
unsigned int numGlyphs;
hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, &numGlyphs);
hb_glyph_position_t* positions = hb_buffer_get_glyph_positions(buffer, NULL);
+ if (numGlyphs)
+ {
+ mAdvances[info[0].cluster - start] += letterSpaceHalf;
+ x += letterSpaceHalf;
+ }
for (unsigned int i = 0; i < numGlyphs; i++) {
#ifdef VERBOSE
std::cout << positions[i].x_advance << " " << positions[i].y_advance << " " << positions[i].x_offset << " " << positions[i].y_offset << std::endl; std::cout << "DoLayout " << info[i].codepoint <<
": " << HBFixedToFloat(positions[i].x_advance) << "; " << positions[i].x_offset << ", " << positions[i].y_offset << std::endl;
#endif
+ if (i > 0 && info[i - 1].cluster != info[i].cluster) {
+ mAdvances[info[i - 1].cluster - start] += letterSpaceHalf;
+ mAdvances[info[i].cluster - start] += letterSpaceHalf;
+ x += letterSpaceHalf;
+ }
+
hb_codepoint_t glyph_ix = info[i].codepoint;
float xoff = HBFixedToFloat(positions[i].x_offset);
float yoff = -HBFixedToFloat(positions[i].y_offset);
@@ -705,10 +738,14 @@ void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t
ctx->paint.font->GetBounds(&glyphBounds, glyph_ix, ctx->paint);
glyphBounds.offset(x + xoff, y + yoff);
mBounds.join(glyphBounds);
- size_t cluster = info[i].cluster - start;
- mAdvances[cluster] += xAdvance;
+ mAdvances[info[i].cluster - start] += xAdvance;
x += xAdvance;
}
+ if (numGlyphs)
+ {
+ mAdvances[info[numGlyphs - 1].cluster - start] += letterSpaceHalf;
+ x += letterSpaceHalf;
+ }
}
}
mAdvance = x;