提交 8e7a3dae 编写于 作者: B Behdad Esfahbod

Add letter-spacing support

Bug: 15594400
Change-Id: Ied94d7674be4097b0f44c9b0770d3294dc6433c1
上级 4422f4dd
...@@ -30,6 +30,7 @@ enum CssTag { ...@@ -30,6 +30,7 @@ enum CssTag {
fontStyle, fontStyle,
fontWeight, fontWeight,
cssLang, cssLang,
letterSpacing,
minikinBidi, minikinBidi,
minikinHinting, minikinHinting,
minikinVariant, minikinVariant,
...@@ -44,6 +45,7 @@ const std::string cssTagNames[] = { ...@@ -44,6 +45,7 @@ const std::string cssTagNames[] = {
"font-style", "font-style",
"font-weight", "font-weight",
"lang", "lang",
"letter-spacing",
"-minikin-bidi", "-minikin-bidi",
"-minikin-hinting", "-minikin-hinting",
"-minikin-variant", "-minikin-variant",
......
...@@ -34,6 +34,7 @@ struct MinikinPaint { ...@@ -34,6 +34,7 @@ struct MinikinPaint {
float size; float size;
float scaleX; float scaleX;
float skewX; float skewX;
float letterSpacing;
uint32_t paintFlags; uint32_t paintFlags;
FontFakery fakery; FontFakery fakery;
}; };
......
...@@ -44,6 +44,7 @@ static CssTag parseTag(const string str, size_t off, size_t len) { ...@@ -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; if (strEqC(str, off, len, "font-style")) return fontStyle;
} else if (c == 'l') { } else if (c == 'l') {
if (strEqC(str, off, len, "lang")) return cssLang; if (strEqC(str, off, len, "lang")) return cssLang;
if (strEqC(str, off, len, "letter-spacing")) return letterSpacing;
} else if (c == '-') { } else if (c == '-') {
if (strEqC(str, off, len, "-minikin-bidi")) return minikinBidi; if (strEqC(str, off, len, "-minikin-bidi")) return minikinBidi;
if (strEqC(str, off, len, "-minikin-hinting")) return minikinHinting; if (strEqC(str, off, len, "-minikin-hinting")) return minikinHinting;
......
...@@ -64,6 +64,7 @@ public: ...@@ -64,6 +64,7 @@ public:
const uint16_t* chars, size_t start, size_t count, size_t nchars, bool dir) const uint16_t* chars, size_t start, size_t count, size_t nchars, bool dir)
: mStart(start), mCount(count), mId(collection->getId()), mStyle(style), : mStart(start), mCount(count), mId(collection->getId()), mStyle(style),
mSize(paint.size), mScaleX(paint.scaleX), mSkewX(paint.skewX), mSize(paint.size), mScaleX(paint.scaleX), mSkewX(paint.skewX),
mLetterSpacing(paint.letterSpacing),
mPaintFlags(paint.paintFlags), mIsRtl(dir) { mPaintFlags(paint.paintFlags), mIsRtl(dir) {
mText.setTo(chars, nchars); mText.setTo(chars, nchars);
} }
...@@ -81,6 +82,7 @@ private: ...@@ -81,6 +82,7 @@ private:
float mSize; float mSize;
float mScaleX; float mScaleX;
float mSkewX; float mSkewX;
float mLetterSpacing;
int32_t mPaintFlags; int32_t mPaintFlags;
bool mIsRtl; bool mIsRtl;
// Note: any fields added to MinikinPaint must also be reflected here. // Note: any fields added to MinikinPaint must also be reflected here.
...@@ -144,6 +146,7 @@ bool LayoutCacheKey::operator==(const LayoutCacheKey& other) const { ...@@ -144,6 +146,7 @@ bool LayoutCacheKey::operator==(const LayoutCacheKey& other) const {
&& mSize == other.mSize && mSize == other.mSize
&& mScaleX == other.mScaleX && mScaleX == other.mScaleX
&& mSkewX == other.mSkewX && mSkewX == other.mSkewX
&& mLetterSpacing == other.mLetterSpacing
&& mPaintFlags == other.mPaintFlags && mPaintFlags == other.mPaintFlags
&& mIsRtl == other.mIsRtl && mIsRtl == other.mIsRtl
&& mText == other.mText; && mText == other.mText;
...@@ -157,6 +160,7 @@ hash_t LayoutCacheKey::hash() const { ...@@ -157,6 +160,7 @@ hash_t LayoutCacheKey::hash() const {
hash = JenkinsHashMix(hash, hash_type(mSize)); hash = JenkinsHashMix(hash, hash_type(mSize));
hash = JenkinsHashMix(hash, hash_type(mScaleX)); hash = JenkinsHashMix(hash, hash_type(mScaleX));
hash = JenkinsHashMix(hash, hash_type(mSkewX)); hash = JenkinsHashMix(hash, hash_type(mSkewX));
hash = JenkinsHashMix(hash, hash_type(mLetterSpacing));
hash = JenkinsHashMix(hash, hash_type(mPaintFlags)); hash = JenkinsHashMix(hash, hash_type(mPaintFlags));
hash = JenkinsHashMix(hash, hash_type(mIsRtl)); hash = JenkinsHashMix(hash, hash_type(mIsRtl));
hash = JenkinsHashMixShorts(hash, mText.string(), mText.size()); 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 ...@@ -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.props.value(fontScaleX).getDoubleValue() : 1;
ctx.paint.skewX = ctx.props.hasTag(fontSkewX) ctx.paint.skewX = ctx.props.hasTag(fontSkewX)
? ctx.props.value(fontSkewX).getDoubleValue() : 0; ? 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.paint.paintFlags = ctx.props.hasTag(paintFlags)
? ctx.props.value(paintFlags).getUintValue() : 0; ? ctx.props.value(paintFlags).getUintValue() : 0;
int bidiFlags = ctx.props.hasTag(minikinBidi) ? ctx.props.value(minikinBidi).getIntValue() : 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 ...@@ -646,8 +652,25 @@ void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t
} }
vector<hb_feature_t> features; 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); 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 x = mAdvance;
float y = 0; float y = 0;
for (size_t run_ix = 0; run_ix < items.size(); run_ix++) { 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 ...@@ -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 << std::cout << "Run " << run_ix << ", font " << font_ix <<
" [" << run.start << ":" << run.end << "]" << std::endl; " [" << run.start << ":" << run.end << "]" << std::endl;
#endif #endif
double size = ctx->paint.size;
double scaleX = ctx->paint.scaleX;
hb_font_set_ppem(hbFont, size * scaleX, size); hb_font_set_ppem(hbFont, size * scaleX, size);
hb_font_set_scale(hbFont, HBFloatToFixed(size * scaleX), HBFloatToFixed(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 ...@@ -689,11 +711,22 @@ void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t
unsigned int numGlyphs; unsigned int numGlyphs;
hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, &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); 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++) { for (unsigned int i = 0; i < numGlyphs; i++) {
#ifdef VERBOSE #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 << 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; ": " << HBFixedToFloat(positions[i].x_advance) << "; " << positions[i].x_offset << ", " << positions[i].y_offset << std::endl;
#endif #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; hb_codepoint_t glyph_ix = info[i].codepoint;
float xoff = HBFixedToFloat(positions[i].x_offset); float xoff = HBFixedToFloat(positions[i].x_offset);
float yoff = -HBFixedToFloat(positions[i].y_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 ...@@ -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); ctx->paint.font->GetBounds(&glyphBounds, glyph_ix, ctx->paint);
glyphBounds.offset(x + xoff, y + yoff); glyphBounds.offset(x + xoff, y + yoff);
mBounds.join(glyphBounds); mBounds.join(glyphBounds);
size_t cluster = info[i].cluster - start; mAdvances[info[i].cluster - start] += xAdvance;
mAdvances[cluster] += xAdvance;
x += xAdvance; x += xAdvance;
} }
if (numGlyphs)
{
mAdvances[info[numGlyphs - 1].cluster - start] += letterSpaceHalf;
x += letterSpaceHalf;
}
} }
} }
mAdvance = x; mAdvance = x;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册