のねのBlog

パソコンの問題や、ソフトウェアの開発で起きた問題など書いていきます。よろしくお願いします^^。

getInstanceForChar

    588 void Layout::doLayoutRunCached(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
    589         bool isRtl, LayoutContext* ctx, size_t dstStart) {
    590     if (!isRtl) {
    591         // left to right
    592         size_t wordstart = start == bufSize ? start : getPrevWordBreak(buf, start + 1);
    593         size_t wordend;
    594         for (size_t iter = start; iter < start + count; iter = wordend) {
    595             wordend = getNextWordBreak(buf, iter, bufSize);
    596             size_t wordcount = std::min(start + count, wordend) - iter;
    597             doLayoutWord(buf + wordstart, iter - wordstart, wordcount, wordend - wordstart,
    598                     isRtl, ctx, iter - dstStart);
    599             wordstart = wordend;
    600         }
    601     } else {
    602         // right to left
    603         size_t wordstart;
    604         size_t end = start + count;
    605         size_t wordend = end == 0 ? 0 : getNextWordBreak(buf, end - 1, bufSize);
    606         for (size_t iter = end; iter > start; iter = wordstart) {
    607             wordstart = getPrevWordBreak(buf, iter);
    608             size_t bufStart = std::max(start, wordstart);
    609             doLayoutWord(buf + wordstart, bufStart - wordstart, iter - bufStart,
    610                     wordend - wordstart, isRtl, ctx, bufStart - dstStart);
    611             wordend = wordstart;
    612         }
    613     }
    614 }
    616 void Layout::doLayoutWord(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
    617         bool isRtl, LayoutContext* ctx, size_t bufStart) {
    618     LayoutCache& cache = LayoutEngine::getInstance().layoutCache;
    619     LayoutCacheKey key(mCollection, ctx->paint, ctx->style, buf, start, count, bufSize, isRtl);
    620     bool skipCache = ctx->paint.skipCache();
    621     if (skipCache) {
    622         Layout layout;
    623         key.doLayout(&layout, ctx, mCollection);
    624         appendLayout(&layout, bufStart);
    625     } else {
    626         Layout* layout = cache.get(key, ctx, mCollection);
    627         appendLayout(layout, bufStart);
    628     }
    629 }
    652 void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
    653         bool isRtl, LayoutContext* ctx) {
    654     hb_buffer_t* buffer = LayoutEngine::getInstance().hbBuffer;
    655     vector<FontCollection::Run> items;
    656     mCollection->itemize(buf + start, count, ctx->style, &items); <=====
    657     if (isRtl) {
    658         std::reverse(items.begin(), items.end());
    659     }
    660 
    661     vector<hb_feature_t> features;
    662     // Disable default-on non-required ligature features if letter-spacing
    663     // See http://dev.w3.org/csswg/css-text-3/#letter-spacing-property
    664     // "When the effective spacing between two characters is not zero (due to
    665     // either justification or a non-zero value of letter-spacing), user agents
    666     // should not apply optional ligatures."
    667     if (fabs(ctx->paint.letterSpacing) > 0.03)
    668     {
    669         static const hb_feature_t no_liga = { HB_TAG('l', 'i', 'g', 'a'), 0, 0, ~0u };
    670         static const hb_feature_t no_clig = { HB_TAG('c', 'l', 'i', 'g'), 0, 0, ~0u };
    671         features.push_back(no_liga);
    672         features.push_back(no_clig);
    673     }
    674     addFeatures(ctx->paint.fontFeatureSettings, &features);
    675 
    676     double size = ctx->paint.size;
    677     double scaleX = ctx->paint.scaleX;
    678     double letterSpace = ctx->paint.letterSpacing * size * scaleX;
    679     double letterSpaceHalfLeft;
    680     if ((ctx->paint.paintFlags & LinearTextFlag) == 0) {
    681         letterSpace = round(letterSpace);
    682         letterSpaceHalfLeft = floor(letterSpace * 0.5);
    683     } else {
    684         letterSpaceHalfLeft = letterSpace * 0.5;
    685     }
    686     double letterSpaceHalfRight = letterSpace - letterSpaceHalfLeft;
    687 
    688     float x = mAdvance;
    689     float y = 0;
    690     for (size_t run_ix = 0; run_ix < items.size(); run_ix++) {
    691         FontCollection::Run &run = items[run_ix];
    692         if (run.fakedFont.font == NULL) {
    693             ALOGE("no font for run starting u+%04x length %d", buf[run.start], run.end - run.start);
    694             continue;
    695         }
    696         int font_ix = findFace(run.fakedFont, ctx);
    697         ctx->paint.font = mFaces[font_ix].font;
    698         ctx->paint.fakery = mFaces[font_ix].fakery;
    699         hb_font_t* hbFont = ctx->hbFonts[font_ix];
    700 #ifdef VERBOSE
    701         std::cout << "Run " << run_ix << ", font " << font_ix <<
    702             " [" << run.start << ":" << run.end << "]" << std::endl;
    703 #endif
    704 
    705         hb_font_set_ppem(hbFont, size * scaleX, size);
    706         hb_font_set_scale(hbFont, HBFloatToFixed(size * scaleX), HBFloatToFixed(size));
    707 
    708         // TODO: if there are multiple scripts within a font in an RTL run,
    709         // we need to reorder those runs. This is unlikely with our current
    710         // font stack, but should be done for correctness.
    711         ssize_t srunend;
    712         for (ssize_t srunstart = run.start; srunstart < run.end; srunstart = srunend) {
    713             srunend = srunstart;
    714             hb_script_t script = getScriptRun(buf + start, run.end, &srunend);
    715 
    716             hb_buffer_reset(buffer);
    717             hb_buffer_set_script(buffer, script);
    718             hb_buffer_set_direction(buffer, isRtl? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
    719             FontLanguage language = ctx->style.getLanguage();
    720             if (language) {
    721                 string lang = language.getString();
    722                 hb_buffer_set_language(buffer, hb_language_from_string(lang.c_str(), -1));
    723             }
    724             hb_buffer_add_utf16(buffer, buf, bufSize, srunstart + start, srunend - srunstart);
    725             hb_shape(hbFont, buffer, features.empty() ? NULL : &features[0], features.size());
    726             unsigned int numGlyphs;
    727             hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, &numGlyphs);
    728             hb_glyph_position_t* positions = hb_buffer_get_glyph_positions(buffer, NULL);
    729             if (numGlyphs)
    730             {
    731                 mAdvances[info[0].cluster - start] += letterSpaceHalfLeft;
    732                 x += letterSpaceHalfLeft;
    733             }
    734             for (unsigned int i = 0; i < numGlyphs; i++) {
    735     #ifdef VERBOSE
    736                 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 <<
    737                 ": " << HBFixedToFloat(positions[i].x_advance) << "; " << positions[i].x_offset << ", " << positions[i].y_offset << std::endl;
    738     #endif
    739                 if (i > 0 && info[i - 1].cluster != info[i].cluster) {
    740                     mAdvances[info[i - 1].cluster - start] += letterSpaceHalfRight;
    741                     mAdvances[info[i].cluster - start] += letterSpaceHalfLeft;
    742                     x += letterSpace;
    743                 }
    744 
    745                 hb_codepoint_t glyph_ix = info[i].codepoint;
    746                 float xoff = HBFixedToFloat(positions[i].x_offset);
    747                 float yoff = -HBFixedToFloat(positions[i].y_offset);
    748                 xoff += yoff * ctx->paint.skewX;
    749                 LayoutGlyph glyph = {font_ix, glyph_ix, x + xoff, y + yoff};
    750                 mGlyphs.push_back(glyph);
    751                 float xAdvance = HBFixedToFloat(positions[i].x_advance);
    752                 if ((ctx->paint.paintFlags & LinearTextFlag) == 0) {
    753                     xAdvance = roundf(xAdvance);
    754                 }
    755                 MinikinRect glyphBounds;
    756                 ctx->paint.font->GetBounds(&glyphBounds, glyph_ix, ctx->paint);
    757                 glyphBounds.offset(x + xoff, y + yoff);
    758                 mBounds.join(glyphBounds);
    759                 mAdvances[info[i].cluster - start] += xAdvance;
    760                 x += xAdvance;
    761             }
    762             if (numGlyphs)
    763             {
    764                 mAdvances[info[numGlyphs - 1].cluster - start] += letterSpaceHalfRight;
    765                 x += letterSpaceHalfRight;
    766             }
    767         }
    768     }
    769     mAdvance = x;
    770 }
    182 void FontCollection::itemize(const uint16_t *string, size_t string_size, FontStyle style,
    183         vector<Run>* result) const {
    184     FontLanguage lang = style.getLanguage();
    185     int variant = style.getVariant();
    186     const FontInstance* lastInstance = NULL;
    187     Run* run = NULL;
    188     int nShorts;
    189     for (size_t i = 0; i < string_size; i += nShorts) {
    190         nShorts = 1;
    191         uint32_t ch = string[i];
    192         // sigh, decode UTF-16 by hand here
    193         if ((ch & 0xfc00) == 0xd800) {
    194             if ((i + 1) < string_size) {
    195                 ch = 0x10000 + ((ch & 0x3ff) << 10) + (string[i + 1] & 0x3ff);
    196                 nShorts = 2;
    197             }
    198         }
    199         // Continue using existing font as long as it has coverage and is whitelisted
    200         if (lastInstance == NULL
    201                 || !(isStickyWhitelisted(ch) && lastInstance->mCoverage->get(ch))) {
    202             const FontInstance* instance = getInstanceForChar(ch, lang, variant);  <=====
    203             if (i == 0 || instance != lastInstance) {
    204                 size_t start = i;
    205                 // Workaround for Emoji keycap until we implement per-cluster font
    206                 // selection: if keycap is found in a different font that also
    207                 // supports previous char, attach previous char to the new run.
    208                 // Only handles non-surrogate characters.
    209                 // Bug 7557244.
    210                 if (ch == KEYCAP && i && instance && instance->mCoverage->get(string[i - 1])) {
    211                     run->end--;
    212                     if (run->start == run->end) {
    213                         result->pop_back();
    214                     }
    215                     start--;
    216                 }
    217                 Run dummy;
    218                 result->push_back(dummy);
    219                 run = &result->back();
    220                 if (instance == NULL) {
    221                     run->fakedFont.font = NULL;
    222                 } else {
    223                     run->fakedFont = instance->mFamily->getClosestMatch(style);
    224                 }
    225                 lastInstance = instance;
    226                 run->start = start;
    227             }
    228         }
    229         run->end = i + nShorts;
    230     }
    231 }
    114 // Implement heuristic for choosing best-match font. Here are the rules:
        // ベストマッチのフォントを選択するためのヒューリスティックを実装します。
        //ここでのルールは以下のとおりです。
    115 // 1. If first font in the collection has the character, it wins.
        //    コレクション内の最初のフォントが文字を持っている場合、それは勝つ。
    116 // 2. If a font matches both language and script, it gets a score of 4.
        //    フォントが言語とスクリプトの両方に一致する場合、それは4のスコアを取得します。
    117 // 3. If a font matches just language, it gets a score of 2.
        //    フォントは単に言語と一致する場合は、2のスコアを得る。
    118 // 4. Matching the "compact" or "elegant" variant adds one to the score.
        //    「コンパクト」または「エレガント」バリアントを一致させることは、スコアに1を加算。
    119 // 5. Highest score wins, with ties resolved to the first font.
        //    最高スコアが最初のフォントに解決タイで、勝つ。

    120 const FontCollection::FontInstance* FontCollection::getInstanceForChar(uint32_t ch,
    121             FontLanguage lang, int variant) const {
    122     if (ch >= mMaxChar) {
    123         return NULL;
    124     }
    125     const Range& range = mRanges[ch >> kLogCharsPerPage];
    126 #ifdef VERBOSE_DEBUG
    127     ALOGD("querying range %d:%d\n", range.start, range.end);
    128 #endif
    129     const FontInstance* bestInstance = NULL;
    130     int bestScore = -1;
    131     for (size_t i = range.start; i < range.end; i++) {
    132         const FontInstance* instance = mInstanceVec[i];
    133         if (instance->mCoverage->get(ch)) {
    134             FontFamily* family = instance->mFamily;
    135             // First font family in collection always matches
    136             if (mInstances[0].mFamily == family) {
    137                 return instance;
    138             }
    139             int score = lang.match(family->lang()) * 2;
    140             if (variant != 0 && variant == family->variant()) {
    141                 score++;
    142             }
    143             if (score > bestScore) {
    144                 bestScore = score;
    145                 bestInstance = instance;
    146             }
    147         }
    148     }
    149     if (bestInstance == NULL && !mInstanceVec.empty()) {
    150         UErrorCode errorCode = U_ZERO_ERROR;
    151         const UNormalizer2* normalizer = unorm2_getNFDInstance(&errorCode);
    152         if (U_SUCCESS(errorCode)) {
    153             UChar decomposed[4];
    154             int len = unorm2_getRawDecomposition(normalizer, ch, decomposed, 4, &errorCode);
    155             if (U_SUCCESS(errorCode) && len > 0) {
    156                 int off = 0;
    157                 U16_NEXT_UNSAFE(decomposed, off, ch);
    158                 return getInstanceForChar(ch, lang, variant);
    159             }
    160         }
    161         bestInstance = &mInstances[0];
    162     }
    163     return bestInstance;
    164 }