Support for scaleX and skewX

Adds pseudo-css properties for scaleX and skewX, as well as paint flags,
and plumb them through to the MinikinPaint abstraction and to Harfbuzz,
to support nontrivial scale and stretch of text.

This is the Minikin part of the fix for bug 15186705 "Usability of the
suggestion strip in recent OTA's is severely reduced"

Change-Id: Ifa60355e086e4691ff92c5d50d84eb7cea0fea95
This commit is contained in:
Raph Levien
2014-05-30 23:38:56 -07:00
parent 1391c37ea9
commit 23801bf449
4 changed files with 43 additions and 15 deletions

View File

@@ -24,24 +24,30 @@ namespace android {
enum CssTag {
unknown,
fontScaleX,
fontSize,
fontSkewX,
fontStyle,
fontWeight,
cssLang,
minikinBidi,
minikinHinting,
minikinVariant,
paintFlags,
};
const std::string cssTagNames[] = {
"unknown",
"font-scale-x",
"font-size",
"font-skew-x",
"font-style",
"font-weight",
"lang",
"-minikin-bidi",
"-minikin-hinting",
"-minikin-variant",
"-paint-flags",
};
class CssValue {
@@ -62,7 +68,7 @@ public:
mType(FLOAT), floatValue(v), mUnits(SCALAR) { }
Type getType() const { return mType; }
double getFloatValue() const { return floatValue; }
int getIntValue() const { return floatValue; }
int32_t getIntValue() const { return floatValue; }
std::string getStringValue() const { return stringValue; }
std::string toString(CssTag tag) const;
void setFloatValue(double v) {

View File

@@ -31,7 +31,9 @@ class MinikinFont;
struct MinikinPaint {
MinikinFont *font;
float size;
// todo: skew, stretch, hinting
float scaleX;
float skewX;
int32_t paintFlags;
};
struct MinikinRect {

View File

@@ -37,7 +37,9 @@ static CssTag parseTag(const string str, size_t off, size_t len) {
if (len == 0) return unknown;
char c = str[off];
if (c == 'f') {
if (strEqC(str, off, len, "font-scale-x")) return fontScaleX;
if (strEqC(str, off, len, "font-size")) return fontSize;
if (strEqC(str, off, len, "font-skew-x")) return fontSkewX;
if (strEqC(str, off, len, "font-weight")) return fontWeight;
if (strEqC(str, off, len, "font-style")) return fontStyle;
} else if (c == 'l') {
@@ -46,6 +48,7 @@ static CssTag parseTag(const string str, size_t off, size_t len) {
if (strEqC(str, off, len, "-minikin-bidi")) return minikinBidi;
if (strEqC(str, off, len, "-minikin-hinting")) return minikinHinting;
if (strEqC(str, off, len, "-minikin-variant")) return minikinVariant;
if (strEqC(str, off, len, "-paint-flags")) return paintFlags;
}
return unknown;
}

View File

@@ -63,7 +63,8 @@ public:
LayoutCacheKey(const FontCollection* collection, const MinikinPaint& paint, FontStyle style,
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), mIsRtl(dir) {
mSize(paint.size), mScaleX(paint.scaleX), mSkewX(paint.skewX),
mPaintFlags(paint.paintFlags), mIsRtl(dir) {
mText.setTo(chars, nchars);
}
bool operator==(const LayoutCacheKey &other) const;
@@ -78,6 +79,9 @@ private:
uint32_t mId; // for the font collection
FontStyle mStyle;
float mSize;
float mScaleX;
float mSkewX;
int mPaintFlags;
bool mIsRtl;
// Note: any fields added to MinikinPaint must also be reflected here.
// TODO: language matching (possibly integrate into style)
@@ -133,13 +137,16 @@ public:
ANDROID_SINGLETON_STATIC_INSTANCE(LayoutEngine);
bool LayoutCacheKey::operator==(const LayoutCacheKey& other) const {
return mId == other.mId &&
mStart == other.mStart &&
mCount == other.mCount &&
mStyle == other.mStyle &&
mSize == other.mSize &&
mIsRtl == other.mIsRtl &&
mText == other.mText;
return mId == other.mId
&& mStart == other.mStart
&& mCount == other.mCount
&& mStyle == other.mStyle
&& mSize == other.mSize
&& mScaleX == other.mScaleX
&& mSkewX == other.mSkewX
&& mPaintFlags == other.mPaintFlags
&& mIsRtl == other.mIsRtl
&& mText == other.mText;
}
hash_t LayoutCacheKey::hash() const {
@@ -148,6 +155,9 @@ hash_t LayoutCacheKey::hash() const {
hash = JenkinsHashMix(hash, mCount);
hash = JenkinsHashMix(hash, hash_type(mStyle));
hash = JenkinsHashMix(hash, hash_type(mSize));
hash = JenkinsHashMix(hash, hash_type(mScaleX));
hash = JenkinsHashMix(hash, hash_type(mSkewX));
hash = JenkinsHashMix(hash, hash_type(mPaintFlags));
hash = JenkinsHashMix(hash, hash_type(mIsRtl));
hash = JenkinsHashMixShorts(hash, mText.string(), mText.size());
return JenkinsHashWhiten(hash);
@@ -502,8 +512,13 @@ void Layout::doLayout(const uint16_t* buf, size_t start, size_t count, size_t bu
ctx.props.parse(css);
ctx.style = styleFromCss(ctx.props);
double size = ctx.props.value(fontSize).getFloatValue();
ctx.paint.size = size;
ctx.paint.size = ctx.props.value(fontSize).getFloatValue();
ctx.paint.scaleX = ctx.props.hasTag(fontScaleX)
? ctx.props.value(fontScaleX).getFloatValue() : 1;
ctx.paint.skewX = ctx.props.hasTag(fontSkewX)
? ctx.props.value(fontSkewX).getFloatValue() : 0;
ctx.paint.paintFlags = ctx.props.hasTag(paintFlags)
?ctx.props.value(paintFlags).getIntValue() : 0;
int bidiFlags = ctx.props.hasTag(minikinBidi) ? ctx.props.value(minikinBidi).getIntValue() : 0;
bool isRtl = (bidiFlags & kDirection_Mask) != 0;
bool doSingleRun = true;
@@ -635,8 +650,9 @@ void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t
" [" << run.start << ":" << run.end << "]" << std::endl;
#endif
double size = ctx->paint.size;
hb_font_set_ppem(hbFont, size, size);
hb_font_set_scale(hbFont, HBFloatToFixed(size), HBFloatToFixed(size));
double scaleX = ctx->paint.scaleX;
hb_font_set_ppem(hbFont, size * scaleX, size);
hb_font_set_scale(hbFont, HBFloatToFixed(size * scaleX), HBFloatToFixed(size));
// TODO: if there are multiple scripts within a font in an RTL run,
// we need to reorder those runs. This is unlikely with our current
@@ -665,7 +681,8 @@ void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t
#endif
hb_codepoint_t glyph_ix = info[i].codepoint;
float xoff = HBFixedToFloat(positions[i].x_offset);
float yoff = HBFixedToFloat(positions[i].y_offset);
float yoff = -HBFixedToFloat(positions[i].y_offset);
xoff += yoff * ctx->paint.skewX;
LayoutGlyph glyph = {font_ix, glyph_ix, x + xoff, y + yoff};
mGlyphs.push_back(glyph);
float xAdvance = HBFixedToFloat(positions[i].x_advance);