summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeigo Nonaka <nona@google.com>2018-02-28 12:54:16 -0800
committerSeigo Nonaka <nona@google.com>2018-03-01 02:25:51 +0000
commitdd088da327736a22ef1ea8a77d5425886ed10fbe (patch)
tree8264da2b0d0fd66c67081553ebdbcb47c9a7a653
parent0ed718b60194bb69d30a5770fe8a1444dbdfac35 (diff)
downloadminikin-dd088da327736a22ef1ea8a77d5425886ed10fbe.tar.gz
Refactoring: Remove LayoutContext
LayoutContext is no longer necessary. Pass MinikinPaint reference instead. No performance regression is expected. This CL changes the returned type of the findOrPushBackFace from int to uint8_t. 8 bits are enough for keeping the fonts since font collection can hold up to 255 font families. StaticLayout creation time: PrecomputedText NoStyled Balanced Hyphenation : 686,921 -> 690,947: (+0.6%) PrecomputedText NoStyled Balanced NoHyphenation: 520,043 -> 519,032: (-0.2%) PrecomputedText NoStyled Greedy Hyphenation : 464,292 -> 460,530: (-0.8%) PrecomputedText NoStyled Greedy NoHyphenation : 465,015 -> 465,243: (+0.0%) Styled Hyphenation : 15,398,146 -> 15,416,375: (+0.1%) Styled Hyphenation WidthOnly : 15,406,933 -> 15,394,211: (-0.1%) Styled NoHyphenation : 14,941,810 -> 15,006,610: (+0.4%) Styled NoHyphenation WidthOnly : 14,971,729 -> 14,934,425: (-0.2%) PrecomputedText creation time: Hyphenation : 18,037,023 -> 17,970,727: (-0.4%) Hyphenation WidthOnly : 18,033,921 -> 17,849,604: (-1.0%) NoHyphenation : 7,479,819 -> 7,386,944: (-1.2%) NoHyphenation WidthOnly : 7,485,902 -> 7,442,596: (-0.6%) RandomText Balanced Hyphenation : 18,130,594 -> 18,073,113: (-0.3%) RandomText Balanced NoHyphenation : 7,480,741 -> 7,444,878: (-0.5%) RandomText Greedy Hyphenation : 7,390,886 -> 7,429,952: (+0.5%) RandomText Greedy NoHyphenation : 7,423,729 -> 7,393,021: (-0.4%) StaticLayout draw time: PrecomputedText NoStyled : 541,811 -> 545,123: (+0.6%) PrecomputedText NoStyled WithoutCache : 534,859 -> 525,401: (-1.8%) PrecomputedText Styled : 811,161 -> 810,757: (-0.0%) PrecomputedText Styled WithoutCache : 837,386 -> 837,663: (+0.0%) RandomText NoStyled : 543,035 -> 548,710: (+1.0%) RandomText NoStyled WithoutCache : 6,817,703 -> 6,810,884: (-0.1%) RandomText Styled : 2,926,399 -> 2,898,167: (-1.0%) RandomText Styled WithoutCache : 3,358,838 -> 3,345,799: (-0.4%) Threaded StaticLayout creation time: RandomText Thread 1 : 7,416,925 -> 7,392,303: (-0.3%) RandomText Thread 2 : 7,540,979 -> 7,476,064: (-0.9%) RandomText Thread 4 : 8,356,506 -> 8,476,209: (+1.4%) Bug: 65024629 Test: minikin_test Change-Id: I7ac59abe10bea77b6dcba2f351c5d8b508acd2c3
-rw-r--r--include/minikin/FontCollection.h3
-rw-r--r--include/minikin/Layout.h18
-rw-r--r--libs/minikin/FontCollection.cpp3
-rw-r--r--libs/minikin/Layout.cpp120
4 files changed, 68 insertions, 76 deletions
diff --git a/include/minikin/FontCollection.h b/include/minikin/FontCollection.h
index 46c362d..642bb6f 100644
--- a/include/minikin/FontCollection.h
+++ b/include/minikin/FontCollection.h
@@ -26,6 +26,9 @@
namespace minikin {
+// The maximum number of font families.
+constexpr uint32_t MAX_FAMILY_COUNT = 254;
+
class FontCollection {
public:
explicit FontCollection(const std::vector<std::shared_ptr<FontFamily>>& typefaces);
diff --git a/include/minikin/Layout.h b/include/minikin/Layout.h
index b3ce629..1b16c27 100644
--- a/include/minikin/Layout.h
+++ b/include/minikin/Layout.h
@@ -45,9 +45,6 @@ struct LayoutGlyph {
float y;
};
-// Internal state used during layout operation
-struct LayoutContext;
-
// Must be the same value with Paint.java
enum class Bidi : uint8_t {
LTR = 0b0000, // Must be same with Paint.BIDI_LTR
@@ -146,8 +143,7 @@ private:
FRIEND_TEST(MeasuredTextTest, buildLayoutTest);
// Find a face in the mFaces vector. If not found, push back the entry to mFaces.
- // If ctx is provided, push back hb_font_t to LayoutContext::hbFonts as well.
- int findOrPushBackFace(const FakedFont& face, LayoutContext* ctx);
+ uint8_t findOrPushBackFace(const FakedFont& face);
// Clears layout, ready to be used again
void reset();
@@ -156,19 +152,21 @@ private:
// When layout is not null, layout info will be stored in the object.
// When advances is not null, measurement results will be stored in the array.
static float doLayoutRunCached(const U16StringPiece& textBuf, const Range& range, bool isRtl,
- LayoutContext* ctx, size_t dstStart, StartHyphenEdit startHyphen,
- EndHyphenEdit endHyphen, Layout* layout, float* advances,
- MinikinExtent* extents, LayoutPieces* lpOut);
+ const MinikinPaint& paint, size_t dstStart,
+ StartHyphenEdit startHyphen, EndHyphenEdit endHyphen,
+ Layout* layout, float* advances, MinikinExtent* extents,
+ LayoutPieces* lpOut);
// Lay out a single word
static float doLayoutWord(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
- bool isRtl, LayoutContext* ctx, size_t bufStart,
+ bool isRtl, const MinikinPaint& paint, size_t bufStart,
StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, Layout* layout,
float* advances, MinikinExtent* extents, LayoutPieces* lpOut);
// Lay out a single bidi run
void doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t bufSize, bool isRtl,
- LayoutContext* ctx, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen);
+ const MinikinPaint& paint, StartHyphenEdit startHyphen,
+ EndHyphenEdit endHyphen);
// Append another layout (for example, cached value) into this one
void appendLayout(const Layout& src, size_t start, float extraAdvance);
diff --git a/libs/minikin/FontCollection.cpp b/libs/minikin/FontCollection.cpp
index 222afb2..3d44ab5 100644
--- a/libs/minikin/FontCollection.cpp
+++ b/libs/minikin/FontCollection.cpp
@@ -77,7 +77,8 @@ void FontCollection::init(const vector<std::shared_ptr<FontFamily>>& typefaces)
}
nTypefaces = mFamilies.size();
MINIKIN_ASSERT(nTypefaces > 0, "Font collection must have at least one valid typeface");
- MINIKIN_ASSERT(nTypefaces <= 254, "Font collection may only have up to 254 font families.");
+ MINIKIN_ASSERT(nTypefaces <= MAX_FAMILY_COUNT,
+ "Font collection may only have up to %d font families.", MAX_FAMILY_COUNT);
size_t nPages = (mMaxChar + kPageMask) >> kLogCharsPerPage;
// TODO: Use variation selector map for mRanges construction.
// A font can have a glyph for a base code point and variation selector pair but no glyph for
diff --git a/libs/minikin/Layout.cpp b/libs/minikin/Layout.cpp
index 9327b14..6e3be05 100644
--- a/libs/minikin/Layout.cpp
+++ b/libs/minikin/Layout.cpp
@@ -117,12 +117,6 @@ hb_font_funcs_t* getFontFuncsForEmoji() {
} // namespace
-struct LayoutContext {
- LayoutContext(const MinikinPaint& paint) : paint(paint) {}
- const MinikinPaint& paint;
- std::vector<HbFontUniquePtr> hbFonts; // parallel to mFaces
-};
-
// Layout cache datatypes
class LayoutCacheKey {
@@ -160,11 +154,11 @@ public:
mChars = NULL;
}
- void doLayout(Layout* layout, LayoutContext* ctx) const {
+ void doLayout(Layout* layout, const MinikinPaint& paint) const {
layout->mAdvances.resize(mCount, 0);
layout->mExtents.resize(mCount);
- ctx->hbFonts.clear();
- layout->doLayoutRun(mChars, mStart, mCount, mNchars, mIsRtl, ctx, mStartHyphen, mEndHyphen);
+ layout->doLayoutRun(mChars, mStart, mCount, mNchars, mIsRtl, paint, mStartHyphen,
+ mEndHyphen);
}
private:
@@ -203,18 +197,19 @@ public:
}
// Do not use any LayoutCache function in callback.
- float getOrCreateAndAppend(const U16StringPiece& text, const Range& range, LayoutContext* ctx,
- bool dir, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen,
+ float getOrCreateAndAppend(const U16StringPiece& text, const Range& range,
+ const MinikinPaint& paint, bool dir, StartHyphenEdit startHyphen,
+ EndHyphenEdit endHyphen,
Layout* outLayout, // nullptr if not necessary
float* outAdvances, // nullptr if not necessary
MinikinExtent* outExtents, // nullptr if not necessary
LayoutPieces* outLayoutPiece, // nullptr if not necessary
uint32_t outIndex, // outputStarting index
float wordSpacing) { // additional wordSpacing
- LayoutCacheKey key(text, range, ctx->paint, dir, startHyphen, endHyphen);
- if (ctx->paint.skipCache()) {
+ LayoutCacheKey key(text, range, paint, dir, startHyphen, endHyphen);
+ if (paint.skipCache()) {
Layout layoutForWord;
- key.doLayout(&layoutForWord, ctx);
+ key.doLayout(&layoutForWord, paint);
return appendTo(layoutForWord, outLayout, outAdvances, outExtents, outLayoutPiece,
outIndex, wordSpacing);
}
@@ -233,7 +228,7 @@ public:
// Don't care even if we do the same layout in other thred.
key.copyText();
std::unique_ptr<Layout> layout = std::make_unique<Layout>();
- key.doLayout(layout.get(), ctx);
+ key.doLayout(layout.get(), paint);
float result = appendTo(*layout, outLayout, outAdvances, outExtents, outLayoutPiece,
outIndex, wordSpacing);
{
@@ -370,27 +365,17 @@ void Layout::dump() const {
}
}
-int Layout::findOrPushBackFace(const FakedFont& face, LayoutContext* ctx) {
- unsigned int ix;
- for (ix = 0; ix < mFaces.size(); ix++) {
+uint8_t Layout::findOrPushBackFace(const FakedFont& face) {
+ MINIKIN_ASSERT(mFaces.size() < MAX_FAMILY_COUNT, "mFaces must not exceeds %d",
+ MAX_FAMILY_COUNT);
+ uint8_t ix = 0;
+ for (; ix < mFaces.size(); ix++) {
if (mFaces[ix].font == face.font) {
return ix;
}
}
-
+ ix = mFaces.size();
mFaces.push_back(face);
- // Note: ctx == nullptr means we're copying from the cache, no need to create corresponding
- // hb_font object.
- if (ctx != nullptr) {
- // We override some functions which are not thread safe.
- // Create new hb_font_t from base font.
- HbFontUniquePtr font(hb_font_create_sub_font(face.font->baseFont().get()));
- hb_font_set_funcs(
- font.get(), isColorBitmapFont(font) ? getFontFuncsForEmoji() : getFontFuncs(),
- new SkiaArguments({face.font->typeface().get(), &ctx->paint, face.fakery}),
- [](void* data) { delete reinterpret_cast<SkiaArguments*>(data); });
- ctx->hbFonts.push_back(std::move(font));
- }
return ix;
}
@@ -449,15 +434,13 @@ static bool isScriptOkForLetterspacing(hb_script_t script) {
void Layout::doLayout(const U16StringPiece& textBuf, const Range& range, Bidi bidiFlags,
const MinikinPaint& paint, StartHyphenEdit startHyphen,
EndHyphenEdit endHyphen) {
- LayoutContext ctx(paint);
-
const uint32_t count = range.getLength();
reset();
mAdvances.resize(count, 0);
mExtents.resize(count);
for (const BidiText::RunInfo& runInfo : BidiText(textBuf, range, bidiFlags)) {
- doLayoutRunCached(textBuf, runInfo.range, runInfo.isRtl, &ctx, range.getStart(),
+ doLayoutRunCached(textBuf, runInfo.range, runInfo.isRtl, paint, range.getStart(),
startHyphen, endHyphen, this, nullptr, nullptr, nullptr);
}
}
@@ -466,11 +449,9 @@ void Layout::doLayout(const U16StringPiece& textBuf, const Range& range, Bidi bi
void Layout::addToLayoutPieces(const U16StringPiece& textBuf, const Range& range, Bidi bidiFlag,
const MinikinPaint& paint,
LayoutPieces* out) {
- LayoutContext ctx(paint);
-
float advance = 0;
for (const BidiText::RunInfo& runInfo : BidiText(textBuf, range, bidiFlag)) {
- advance += doLayoutRunCached(textBuf, runInfo.range, runInfo.isRtl, &ctx,
+ advance += doLayoutRunCached(textBuf, runInfo.range, runInfo.isRtl, paint,
0, // Destination start. Not used.
StartHyphenEdit::NO_EDIT, // Hyphen edit, not used.
EndHyphenEdit::NO_EDIT, // Hyphen edit, not used.
@@ -484,23 +465,22 @@ void Layout::addToLayoutPieces(const U16StringPiece& textBuf, const Range& range
float Layout::measureText(const U16StringPiece& textBuf, const Range& range, Bidi bidiFlags,
const MinikinPaint& paint, StartHyphenEdit startHyphen,
EndHyphenEdit endHyphen, float* advances, MinikinExtent* extents) {
- LayoutContext ctx(paint);
-
float advance = 0;
for (const BidiText::RunInfo& runInfo : BidiText(textBuf, range, bidiFlags)) {
const size_t offset = range.toRangeOffset(runInfo.range.getStart());
float* advancesForRun = advances ? advances + offset : nullptr;
MinikinExtent* extentsForRun = extents ? extents + offset : nullptr;
- advance += doLayoutRunCached(textBuf, runInfo.range, runInfo.isRtl, &ctx, 0, startHyphen,
+ advance += doLayoutRunCached(textBuf, runInfo.range, runInfo.isRtl, paint, 0, startHyphen,
endHyphen, NULL, advancesForRun, extentsForRun, nullptr);
}
return advance;
}
float Layout::doLayoutRunCached(const U16StringPiece& textBuf, const Range& range, bool isRtl,
- LayoutContext* ctx, size_t dstStart, StartHyphenEdit startHyphen,
- EndHyphenEdit endHyphen, Layout* layout, float* advances,
- MinikinExtent* extents, LayoutPieces* lpOut) {
+ const MinikinPaint& paint, size_t dstStart,
+ StartHyphenEdit startHyphen, EndHyphenEdit endHyphen,
+ Layout* layout, float* advances, MinikinExtent* extents,
+ LayoutPieces* lpOut) {
if (!range.isValid()) {
return 0.0f; // ICU failed to retrieve the bidi run?
}
@@ -519,7 +499,7 @@ float Layout::doLayoutRunCached(const U16StringPiece& textBuf, const Range& rang
const uint32_t wordcount = std::min(end, wordend) - iter;
const uint32_t offset = iter - start;
advance += doLayoutWord(buf + wordstart, iter - wordstart, wordcount,
- wordend - wordstart, isRtl, ctx, iter - dstStart,
+ wordend - wordstart, isRtl, paint, iter - dstStart,
// Only apply hyphen to the first or last word in the string.
iter == start ? startHyphen : StartHyphenEdit::NO_EDIT,
wordend >= end ? endHyphen : EndHyphenEdit::NO_EDIT, layout,
@@ -536,7 +516,7 @@ float Layout::doLayoutRunCached(const U16StringPiece& textBuf, const Range& rang
uint32_t bufStart = std::max(start, wordstart);
const uint32_t offset = bufStart - start;
advance += doLayoutWord(buf + wordstart, bufStart - wordstart, iter - bufStart,
- wordend - wordstart, isRtl, ctx, bufStart - dstStart,
+ wordend - wordstart, isRtl, paint, bufStart - dstStart,
// Only apply hyphen to the first (rightmost) or last (leftmost)
// word in the string.
wordstart <= start ? startHyphen : StartHyphenEdit::NO_EDIT,
@@ -550,12 +530,12 @@ float Layout::doLayoutRunCached(const U16StringPiece& textBuf, const Range& rang
}
float Layout::doLayoutWord(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
- bool isRtl, LayoutContext* ctx, size_t bufStart,
+ bool isRtl, const MinikinPaint& paint, size_t bufStart,
StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, Layout* layout,
float* advances, MinikinExtent* extents, LayoutPieces* lpOut) {
- float wordSpacing = count == 1 && isWordSpace(buf[start]) ? ctx->paint.wordSpacing : 0;
+ float wordSpacing = count == 1 && isWordSpace(buf[start]) ? paint.wordSpacing : 0;
float advance = LayoutCache::getInstance().getOrCreateAndAppend(
- U16StringPiece(buf, bufSize), Range(start, start + count), ctx, isRtl, startHyphen,
+ U16StringPiece(buf, bufSize), Range(start, start + count), paint, isRtl, startHyphen,
endHyphen, layout, advances, extents, lpOut, bufStart, wordSpacing);
if (wordSpacing != 0) {
@@ -716,12 +696,12 @@ static inline uint32_t addToHbBuffer(const HbBufferUniquePtr& buffer, const uint
}
void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
- bool isRtl, LayoutContext* ctx, StartHyphenEdit startHyphen,
+ bool isRtl, const MinikinPaint& paint, StartHyphenEdit startHyphen,
EndHyphenEdit endHyphen) {
HbBufferUniquePtr buffer(hb_buffer_create());
hb_buffer_set_unicode_funcs(buffer.get(), getUnicodeFunctions());
std::vector<FontCollection::Run> items;
- ctx->paint.font->itemize(buf + start, count, ctx->paint, &items);
+ paint.font->itemize(buf + start, count, paint, &items);
std::vector<hb_feature_t> features;
// Disable default-on non-required ligature features if letter-spacing
@@ -729,16 +709,17 @@ void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t
// "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) {
+ if (fabs(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(ctx->paint.fontFeatureSettings, &features);
+ addFeatures(paint.fontFeatureSettings, &features);
- double size = ctx->paint.size;
- double scaleX = ctx->paint.scaleX;
+ std::vector<HbFontUniquePtr> hbFonts;
+ double size = paint.size;
+ double scaleX = paint.scaleX;
float x = mAdvance;
float y = 0;
@@ -747,11 +728,20 @@ void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t
isRtl ? --run_ix : ++run_ix) {
FontCollection::Run& run = items[run_ix];
const FakedFont& fakedFont = run.fakedFont;
- const int font_ix = findOrPushBackFace(fakedFont, ctx);
- const HbFontUniquePtr& hbFont = ctx->hbFonts[font_ix];
+ const uint8_t font_ix = findOrPushBackFace(fakedFont);
+ if (hbFonts.size() == font_ix) { // findOrPushBackFace push backed the new face.
+ // We override some functions which are not thread safe.
+ HbFontUniquePtr font(hb_font_create_sub_font(fakedFont.font->baseFont().get()));
+ hb_font_set_funcs(
+ font.get(), isColorBitmapFont(font) ? getFontFuncsForEmoji() : getFontFuncs(),
+ new SkiaArguments({fakedFont.font->typeface().get(), &paint, fakedFont.fakery}),
+ [](void* data) { delete reinterpret_cast<SkiaArguments*>(data); });
+ hbFonts.push_back(std::move(font));
+ }
+ const HbFontUniquePtr& hbFont = hbFonts[font_ix];
MinikinExtent verticalExtent;
- fakedFont.font->typeface()->GetFontExtent(&verticalExtent, ctx->paint, fakedFont.fakery);
+ fakedFont.font->typeface()->GetFontExtent(&verticalExtent, paint, fakedFont.fakery);
std::fill(&mExtents[run.start], &mExtents[run.end], verticalExtent);
hb_font_set_ppem(hbFont.get(), size * scaleX, size);
@@ -781,9 +771,9 @@ void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t
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) {
+ if (paint.letterSpacing != 0.0 && isScriptOkForLetterspacing(script)) {
+ letterSpace = paint.letterSpacing * size * scaleX;
+ if ((paint.paintFlags & LinearTextFlag) == 0) {
letterSpace = round(letterSpace);
letterSpaceHalfLeft = floor(letterSpace * 0.5);
} else {
@@ -795,7 +785,7 @@ void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t
hb_buffer_clear_contents(buffer.get());
hb_buffer_set_script(buffer.get(), script);
hb_buffer_set_direction(buffer.get(), isRtl ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
- const LocaleList& localeList = LocaleListCache::getById(ctx->paint.localeListId);
+ const LocaleList& localeList = LocaleListCache::getById(paint.localeListId);
if (localeList.size() != 0) {
hb_language_t hbLanguage = localeList.getHbLanguage(0);
for (size_t i = 0; i < localeList.size(); ++i) {
@@ -840,11 +830,11 @@ void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t
hb_codepoint_t glyph_ix = info[i].codepoint;
float xoff = HBFixedToFloat(positions[i].x_offset);
float yoff = -HBFixedToFloat(positions[i].y_offset);
- xoff += yoff * ctx->paint.skewX;
+ xoff += yoff * paint.skewX;
LayoutGlyph glyph = {font_ix, glyph_ix, x + xoff, y + yoff};
mGlyphs.push_back(glyph);
float xAdvance = HBFixedToFloat(positions[i].x_advance);
- if ((ctx->paint.paintFlags & LinearTextFlag) == 0) {
+ if ((paint.paintFlags & LinearTextFlag) == 0) {
xAdvance = roundf(xAdvance);
}
MinikinRect glyphBounds;
@@ -860,7 +850,7 @@ void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t
glyphBounds.mBottom =
roundf(HBFixedToFloat(-extents.y_bearing - extents.height));
} else {
- fakedFont.font->typeface()->GetBounds(&glyphBounds, glyph_ix, ctx->paint,
+ fakedFont.font->typeface()->GetBounds(&glyphBounds, glyph_ix, paint,
fakedFont.fakery);
}
glyphBounds.offset(xoff, yoff);
@@ -893,7 +883,7 @@ void Layout::appendLayout(const Layout& src, size_t start, float extraAdvance) {
fontMap = new int[src.mFaces.size()];
}
for (size_t i = 0; i < src.mFaces.size(); i++) {
- int font_ix = findOrPushBackFace(src.mFaces[i], nullptr);
+ uint8_t font_ix = findOrPushBackFace(src.mFaces[i]);
fontMap[i] = font_ix;
}
int x0 = mAdvance;