示例#1
0
        // Lay out a single bidi run
        public void doLayoutRun(UInt16[] buf, int start, int count, int bufSize, bool isRtl, LayoutContext ctx, FontCollection collection)
        {
            hb_buffer_t buffer = LayoutEngine.getInstance().hbBuffer;
            vector <FontCollection.Run> items = new vector <FontCollection.Run>();

            collection.itemize(buf + start, count, ctx.style, items);

            vector <hb_feature_t> features = new vector <hb_feature_t>();

            // 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 (Math.Abs(ctx.paint.letterSpacing) > 0.03)
            {
                hb_feature_t no_liga = new hb_feature_t(HB_TAG('l', 'i', 'g', 'a'), 0, 0, ~0u);
                hb_feature_t no_clig = new hb_feature_t(HB_TAG('c', 'l', 'i', 'g'), 0, 0, ~0u);
                features.push_back(no_liga);
                features.push_back(no_clig);
            }
            addFeatures(ctx.paint.fontFeatureSettings, features);

            double size   = ctx.paint.size;
            double scaleX = ctx.paint.scaleX;

            float x = mAdvance;
            float y = 0F;

            for (int run_ix = isRtl ? items.size() - 1 : 0; isRtl?run_ix >= 0 : run_ix < (int)items.size(); isRtl ?--run_ix :++run_ix)
            {
                FontCollection.Run run = items[run_ix];
                if (run.fakedFont.font == null)
                {
                    ALOGE("no font for run starting u+%04x length %d", buf[run.start], run.end - run.start);
                    continue;
                }
                int font_ix = findFace(run.fakedFont, ctx);
                ctx.paint.font   = mFaces[font_ix].font;
                ctx.paint.fakery = mFaces[font_ix].fakery;
                HarfBuzzSharp.Font hbFont = ctx.hbFonts[font_ix];
        #if VERBOSE_DEBUG
                ALOGD("Run %zu, font %d [%d:%d]", run_ix, font_ix, run.start, run.end);
        #endif

                hb_font_set_ppem(hbFont, size * scaleX, size);
                hb_font_set_scale(hbFont, HBFloatToFixed(size * scaleX), HBFloatToFixed(size));

                bool is_color_bitmap_font = isColorBitmapFont(hbFont);

                // 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
                // font stack, but should be done for correctness.

                // Note: scriptRunStart and scriptRunEnd, as well as run.start and run.end,
                // run between 0 and count.
                uint scriptRunEnd;
                for (uint scriptRunStart = run.start; scriptRunStart < run.end; scriptRunStart = scriptRunEnd)
                {
                    scriptRunEnd = scriptRunStart;
                    hb_script_t script = getScriptRun(buf + start, run.end, ref scriptRunEnd);
                    // After the last line, scriptRunEnd is guaranteed to have increased,
                    // since the only time getScriptRun does not increase its iterator is when
                    // it has already reached the end of the buffer. But that can't happen,
                    // since if we have already reached the end of the buffer, we should have
                    // had (scriptRunEnd == run.end), which means (scriptRunStart == run.end)
                    // which is impossible due to the exit condition of the for loop. So we
                    // can be sure that scriptRunEnd > scriptRunStart.

                    double letterSpace          = 0.0;
                    double letterSpaceHalfLeft  = 0.0;
                    double letterSpaceHalfRight = 0.0;

                    if (ctx.paint.letterSpacing != 0.0 && isScriptOkForLetterspacing(new hb_script_t(script)))
                    {
                        letterSpace = ctx.paint.letterSpacing * size * scaleX;
                        if ((ctx.paint.paintFlags & LinearTextFlag) == 0)
                        {
                            letterSpace         = Math.Round(letterSpace);
                            letterSpaceHalfLeft = Math.Floor(letterSpace * 0.5);
                        }
                        else
                        {
                            letterSpaceHalfLeft = letterSpace * 0.5;
                        }
                        letterSpaceHalfRight = letterSpace - letterSpaceHalfLeft;
                    }

                    hb_buffer_clear_contents(buffer);
                    hb_buffer_set_script(buffer, script);
                    hb_buffer_set_direction(buffer, isRtl ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
                    FontLanguages langList = FontLanguageListCache.getById(ctx.style.getLanguageListId());
                    if (langList.size() != 0)
                    {
                        FontLanguage hbLanguage = langList[0];
                        for (int i = 0; i < langList.size(); ++i)
                        {
                            if (langList[i].supportsHbScript(script))
                            {
                                hbLanguage = langList[i];
                                break;
                            }
                        }
                        hb_buffer_set_language(buffer, hbLanguage.getHbLanguage());
                    }

                    uint clusterStart = addToHbBuffer(buffer, new UInt16(buf), start, count, bufSize, scriptRunStart, scriptRunEnd, ctx.paint.hyphenEdit, hbFont);

                    hb_shape(hbFont, buffer, features.empty() ? null : features[0], features.size());
                    uint 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);

                    // At this point in the code, the cluster values in the info buffer
                    // correspond to the input characters with some shift. The cluster value
                    // clusterStart corresponds to the first character passed to HarfBuzz,
                    // which is at buf[start + scriptRunStart] whose advance needs to be saved
                    // into mAdvances[scriptRunStart]. So cluster values need to be reduced by
                    // (clusterStart - scriptRunStart) to get converted to indices of
                    // mAdvances.
                    uint clusterOffset = clusterStart - scriptRunStart;

                    if (numGlyphs != 0)
                    {
                        mAdvances[info[0].cluster - clusterOffset] += letterSpaceHalfLeft;
                        x += letterSpaceHalfLeft;
                    }
                    for (uint i = 0; i < numGlyphs; i++)
                    {
        #if VERBOSE_DEBUG
                        ALOGD("%d %d %d %d", positions[i].x_advance, positions[i].y_advance, positions[i].x_offset, positions[i].y_offset);
                        ALOGD("DoLayout %u: %f; %d, %d", info[i].codepoint, HBFixedToFloat(positions[i].x_advance), positions[i].x_offset, positions[i].y_offset);
        #endif
                        if (i > 0 && info[i - 1].cluster != info[i].cluster)
                        {
                            mAdvances[info[i - 1].cluster - clusterOffset] += letterSpaceHalfRight;
                            mAdvances[info[i].cluster - clusterOffset]     += letterSpaceHalfLeft;
                            x += letterSpace;
                        }

                        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;
                        LayoutGlyph glyph = new LayoutGlyph(font_ix, glyph_ix, x + xoff, y + yoff, (uint)(info[i].cluster - clusterOffset));
                        mGlyphs.push_back(glyph);
                        float xAdvance = HBFixedToFloat(positions[i].x_advance);
                        if ((ctx.paint.paintFlags & LinearTextFlag) == 0)
                        {
                            xAdvance = roundf(xAdvance);
                        }
                        MinikinRect        glyphBounds = new MinikinRect();
                        hb_glyph_extents_t extents     = new hb_glyph_extents_t();
                        if (is_color_bitmap_font && hb_font_get_glyph_extents(hbFont, glyph_ix, extents))
                        {
                            // Note that it is technically possible for a TrueType font to have
                            // outline and embedded bitmap at the same time. We ignore modified
                            // bbox of hinted outline glyphs in that case.
                            glyphBounds.mLeft   = roundf(HBFixedToFloat(extents.x_bearing));
                            glyphBounds.mTop    = roundf(HBFixedToFloat(-extents.y_bearing));
                            glyphBounds.mRight  = roundf(HBFixedToFloat(extents.x_bearing + extents.width));
                            glyphBounds.mBottom = roundf(HBFixedToFloat(-extents.y_bearing - extents.height));
                        }
                        else
                        {
                            ctx.paint.font.GetBounds(glyphBounds, glyph_ix, ctx.paint);
                        }
                        glyphBounds.offset(x + xoff, y + yoff);
                        mBounds.join(glyphBounds);
                        if ((int)(info[i].cluster - clusterOffset) < count)
                        {
                            mAdvances[info[i].cluster - clusterOffset] += xAdvance;
                        }
                        else
                        {
                            ALOGE("cluster %zu (start %zu) out of bounds of count %zu", info[i].cluster - clusterOffset, start, count);
                        }
                        x += xAdvance;
                    }
                    if (numGlyphs != 0)
                    {
                        mAdvances[info[numGlyphs - 1].cluster - clusterOffset] += letterSpaceHalfRight;
                        x += letterSpaceHalfRight;
                    }
                }
            }
            mAdvance = x;
        }