Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 41541825 authored by Chris Craik's avatar Chris Craik Committed by Android (Google) Code Review
Browse files

Use individual glyph positions to determine text bounds.

bug:8766924

Previously text bounds were calculated to be from 0 to totalAdvance in
the X, and from the font's top to bottom. These are incorrect,
especially in light of the font fallback mechanism.

Now, we calculate the bounds of the text as we layout each glyph.
Since these are much tighter bounds in the common case, this
significantly reduces the amount of clipping required (which in turn
enables more aggressive text merging).

Change-Id: I172e5466bf5975bf837af894a9964c41db538746
parent 7f43674d
Loading
Loading
Loading
Loading
+22 −11
Original line number Diff line number Diff line
@@ -318,6 +318,7 @@ hash_t TextLayoutCacheKey::hash() const {
 */
TextLayoutValue::TextLayoutValue(size_t contextCount) :
        mTotalAdvance(0), mElapsedTime(0) {
    mBounds.setEmpty();
    // Give a hint for advances and glyphs vectors size
    mAdvances.setCapacity(contextCount);
    mGlyphs.setCapacity(contextCount);
@@ -345,11 +346,11 @@ TextLayoutShaper::~TextLayoutShaper() {
    hb_buffer_destroy(mBuffer);
}

void TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
        size_t start, size_t count, size_t contextCount, int dirFlags) {

void TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* paint,
        const UChar* chars, size_t start, size_t count, size_t contextCount, int dirFlags) {
    computeValues(paint, chars, start, count, contextCount, dirFlags,
            &value->mAdvances, &value->mTotalAdvance, &value->mGlyphs, &value->mPos);
            &value->mAdvances, &value->mTotalAdvance, &value->mBounds,
            &value->mGlyphs, &value->mPos);
#if DEBUG_ADVANCES
    ALOGD("Advances - start = %d, count = %d, contextCount = %d, totalAdvance = %f", start, count,
            contextCount, value->mTotalAdvance);
@@ -358,7 +359,7 @@ void TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* pain

void TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars,
        size_t start, size_t count, size_t contextCount, int dirFlags,
        Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
        Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance, SkRect* outBounds,
        Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos) {
        *outTotalAdvance = 0;
        if (!count) {
@@ -454,7 +455,7 @@ void TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars,
                                    i, startRun, lengthRun, isRTL);
#endif
                            computeRunValues(paint, chars, startRun, lengthRun, contextCount, isRTL,
                                    outAdvances, outTotalAdvance, outGlyphs, outPos);
                                    outAdvances, outTotalAdvance, outBounds, outGlyphs, outPos);

                        }
                    }
@@ -478,7 +479,7 @@ void TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars,
                    "-- run-start = %d, run-len = %d, isRTL = %d", start, count, isRTL);
#endif
            computeRunValues(paint, chars, start, count, contextCount, isRTL,
                    outAdvances, outTotalAdvance, outGlyphs, outPos);
                    outAdvances, outTotalAdvance, outBounds, outGlyphs, outPos);
        }

#if DEBUG_GLYPHS
@@ -675,7 +676,7 @@ static void logGlyphs(hb_buffer_t* buffer) {

void TextLayoutShaper::computeRunValues(const SkPaint* paint, const UChar* contextChars,
        size_t start, size_t count, size_t contextCount, bool isRTL,
        Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
        Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance, SkRect* outBounds,
        Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos) {
    if (!count) {
        // We cannot shape an empty run.
@@ -749,12 +750,22 @@ void TextLayoutShaper::computeRunValues(const SkPaint* paint, const UChar* conte
            size_t cluster = info[i].cluster - start;
            float xAdvance = HBFixedToFloat(positions[i].x_advance);
            outAdvances->replaceAt(outAdvances->itemAt(cluster) + xAdvance, cluster);
            outGlyphs->add(info[i].codepoint + glyphBaseCount);
            jchar glyphId = info[i].codepoint + glyphBaseCount;
            outGlyphs->add(glyphId);
            float xo = HBFixedToFloat(positions[i].x_offset);
            float yo = -HBFixedToFloat(positions[i].y_offset);
            outPos->add(totalAdvance + xo + yo * skewX);
            outPos->add(yo);

            float xpos = totalAdvance + xo + yo * skewX;
            float ypos = yo;
            outPos->add(xpos);
            outPos->add(ypos);
            totalAdvance += xAdvance;

            // TODO: consider using glyph cache
            const SkGlyph& metrics = mShapingPaint.getGlyphMetrics(glyphId, NULL);
            outBounds->join(xpos + metrics.fLeft, ypos + metrics.fTop,
                    xpos + metrics.fLeft + metrics.fWidth, ypos + metrics.fTop + metrics.fHeight);

        }
    }

+8 −2
Original line number Diff line number Diff line
@@ -134,6 +134,7 @@ public:
    inline const jfloat* getAdvances() const { return mAdvances.array(); }
    inline size_t getAdvancesCount() const { return mAdvances.size(); }
    inline jfloat getTotalAdvance() const { return mTotalAdvance; }
    inline const SkRect& getBounds() const { return mBounds; }
    inline const jchar* getGlyphs() const { return mGlyphs.array(); }
    inline size_t getGlyphsCount() const { return mGlyphs.size(); }
    inline const jfloat* getPos() const { return mPos.array(); }
@@ -149,6 +150,11 @@ public:
     */
    jfloat mTotalAdvance;

    /**
     * Bounds containing all glyphs
     */
    SkRect mBounds;

    /**
     * Glyphs vector
     */
@@ -208,12 +214,12 @@ private:

    void computeValues(const SkPaint* paint, const UChar* chars,
            size_t start, size_t count, size_t contextCount, int dirFlags,
            Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
            Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance, SkRect* outBounds,
            Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos);

    void computeRunValues(const SkPaint* paint, const UChar* chars,
            size_t start, size_t count, size_t contextCount, bool isRTL,
            Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
            Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance, SkRect* outBounds,
            Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos);

    SkTypeface* setCachedTypeface(SkTypeface** typeface, hb_script_t script, SkTypeface::Style style);
+26 −4
Original line number Diff line number Diff line
@@ -574,6 +574,20 @@ static void android_view_GLES20Canvas_resetPaintFilter(JNIEnv* env, jobject claz
// Text
// ----------------------------------------------------------------------------

static float xOffsetForTextAlign(SkPaint* paint, float totalAdvance) {
    switch (paint->getTextAlign()) {
        case SkPaint::kCenter_Align:
            return -totalAdvance / 2.0f;
            break;
        case SkPaint::kRight_Align:
            return -totalAdvance;
            break;
        default:
            break;
    }
    return 0;
}

static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
        jfloat x, jfloat y, int flags, SkPaint* paint) {
    sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
@@ -586,8 +600,12 @@ static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
    jfloat totalAdvance = value->getTotalAdvance();
    const float* positions = value->getPos();
    int bytesCount = glyphsCount * sizeof(jchar);
    renderer->drawText((const char*) glyphs, bytesCount, glyphsCount, x, y,
            positions, paint, totalAdvance);
    const SkRect& r = value->getBounds();
    android::uirenderer::Rect bounds(r.fLeft, r.fTop, r.fRight, r.fBottom);

    renderer->drawText((const char*) glyphs, bytesCount, glyphsCount,
            x + xOffsetForTextAlign(paint, totalAdvance), y, positions,
            paint, totalAdvance, bounds);
}

static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int count,
@@ -617,8 +635,12 @@ static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
    jfloat totalAdvance = value->getTotalAdvance();
    const float* positions = value->getPos();
    int bytesCount = glyphsCount * sizeof(jchar);
    renderer->drawText((const char*) glyphs, bytesCount, glyphsCount, x, y,
            positions, paint, totalAdvance);
    const SkRect& r = value->getBounds();
    android::uirenderer::Rect bounds(r.fLeft, r.fTop, r.fRight, r.fBottom);

    renderer->drawText((const char*) glyphs, bytesCount, glyphsCount,
            x + xOffsetForTextAlign(paint, totalAdvance), y, positions,
            paint, totalAdvance, bounds);
}

static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz,
+4 −4
Original line number Diff line number Diff line
@@ -85,8 +85,8 @@ public:
    }

    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
        DEFER_LOGD("%d  replaying DrawingBatch %p, with %d ops (batch id %x, merge id %p)",
                index, this, mOps.size(), mOps[0]->getBatchId(), mOps[0]->getMergeId());
        DEFER_LOGD("%d  replaying DrawBatch %p, with %d ops (batch id %x, merge id %p)",
                index, this, mOps.size(), getBatchId(), getMergeId());

        status_t status = DrawGlInfo::kStatusDone;
        DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
@@ -193,10 +193,10 @@ public:
    }

    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
        DEFER_LOGD("%d  replaying DrawingBatch %p, with %d ops (batch id %x, merge id %p)",
        DEFER_LOGD("%d  replaying MergingDrawBatch %p, with %d ops (batch id %x, merge id %p)",
                index, this, mOps.size(), getBatchId(), getMergeId());
        if (mOps.size() == 1) {
            return DrawBatch::replay(renderer, dirty, false);
            return DrawBatch::replay(renderer, dirty, 0);
        }

        DrawOp* op = mOps[0];
+11 −20
Original line number Diff line number Diff line
@@ -220,6 +220,9 @@ public:
    DrawBoundedOp(float left, float top, float right, float bottom, SkPaint* paint)
            : DrawOp(paint), mLocalBounds(left, top, right, bottom) {}

    DrawBoundedOp(const Rect& localBounds, SkPaint* paint)
            : DrawOp(paint), mLocalBounds(localBounds) {}

    // Calculates bounds as smallest rect encompassing all points
    // NOTE: requires at least 1 vertex, and doesn't account for stroke size (should be handled in
    // subclass' constructor)
@@ -1272,23 +1275,10 @@ private:
class DrawTextOp : public DrawBoundedOp {
public:
    DrawTextOp(const char* text, int bytesCount, int count, float x, float y,
            const float* positions, SkPaint* paint, float length)
            : DrawBoundedOp(paint), mText(text), mBytesCount(bytesCount), mCount(count),
            mX(x), mY(y), mPositions(positions), mLength(length) {
        // duplicates bounds calculation from OpenGLRenderer::drawText, but doesn't alter mX
        SkPaint::FontMetrics metrics;
        paint->getFontMetrics(&metrics, 0.0f);
        switch (paint->getTextAlign()) {
        case SkPaint::kCenter_Align:
            x -= length / 2.0f;
            break;
        case SkPaint::kRight_Align:
            x -= length;
            break;
        default:
            break;
        }
        mLocalBounds.set(x, mY + metrics.fTop, x + length, mY + metrics.fBottom);
            const float* positions, SkPaint* paint, float totalAdvance, const Rect& bounds)
            : DrawBoundedOp(bounds, paint), mText(text), mBytesCount(bytesCount), mCount(count),
            mX(x), mY(y), mPositions(positions), mTotalAdvance(totalAdvance) {
        mLocalBounds.translate(x,y);
        memset(&mPrecacheTransform.data[0], 0xff, 16 * sizeof(float));
    }

@@ -1314,7 +1304,7 @@ public:

    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
        return renderer.drawText(mText, mBytesCount, mCount, mX, mY,
                mPositions, getPaint(renderer), mLength);
                mPositions, getPaint(renderer), mTotalAdvance, mLocalBounds);
    }

    virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
@@ -1327,7 +1317,8 @@ public:

            DrawTextOp& op = *((DrawTextOp*)ops[i]);
            status |= renderer.drawText(op.mText, op.mBytesCount, op.mCount, op.mX, op.mY,
                    op.mPositions, op.getPaint(renderer), op.mLength, drawOpMode);
                    op.mPositions, op.getPaint(renderer), op.mTotalAdvance, op.mLocalBounds,
                    drawOpMode);
        }
        return status;
    }
@@ -1345,7 +1336,7 @@ private:
    float mX;
    float mY;
    const float* mPositions;
    float mLength;
    float mTotalAdvance;
    mat4 mPrecacheTransform;
};

Loading