Search in sources :

Example 1 with ReplacementSpan

use of android.text.style.ReplacementSpan in project android_frameworks_base by ParanoidAndroid.

the class Layout method getOffsetAtStartOf.

private int getOffsetAtStartOf(int offset) {
    // zero-width characters, look at callers
    if (offset == 0)
        return 0;
    CharSequence text = mText;
    char c = text.charAt(offset);
    if (c >= '�' && c <= '�') {
        char c1 = text.charAt(offset - 1);
        if (c1 >= '�' && c1 <= '�')
            offset -= 1;
    }
    if (mSpannedText) {
        ReplacementSpan[] spans = ((Spanned) text).getSpans(offset, offset, ReplacementSpan.class);
        for (int i = 0; i < spans.length; i++) {
            int start = ((Spanned) text).getSpanStart(spans[i]);
            int end = ((Spanned) text).getSpanEnd(spans[i]);
            if (start < offset && end > offset)
                offset = start;
        }
    }
    return offset;
}
Also used : ReplacementSpan(android.text.style.ReplacementSpan) Paint(android.graphics.Paint)

Example 2 with ReplacementSpan

use of android.text.style.ReplacementSpan in project android_frameworks_base by ParanoidAndroid.

the class TextLine method getOffsetBeforeAfter.

/**
     * Returns the next valid offset within this directional run, skipping
     * conjuncts and zero-width characters.  This should not be called to walk
     * off the end of the line, since the returned values might not be valid
     * on neighboring lines.  If the returned offset is less than zero or
     * greater than the line length, the offset should be recomputed on the
     * preceding or following line, respectively.
     *
     * @param runIndex the run index
     * @param runStart the start of the run
     * @param runLimit the limit of the run
     * @param runIsRtl true if the run is right-to-left
     * @param offset the offset
     * @param after true if the new offset should logically follow the provided
     * offset
     * @return the new offset
     */
private int getOffsetBeforeAfter(int runIndex, int runStart, int runLimit, boolean runIsRtl, int offset, boolean after) {
    if (runIndex < 0 || offset == (after ? mLen : 0)) {
        // return accurate values.  These are a guess.
        if (after) {
            return TextUtils.getOffsetAfter(mText, offset + mStart) - mStart;
        }
        return TextUtils.getOffsetBefore(mText, offset + mStart) - mStart;
    }
    TextPaint wp = mWorkPaint;
    wp.set(mPaint);
    int spanStart = runStart;
    int spanLimit;
    if (mSpanned == null) {
        spanLimit = runLimit;
    } else {
        int target = after ? offset + 1 : offset;
        int limit = mStart + runLimit;
        while (true) {
            spanLimit = mSpanned.nextSpanTransition(mStart + spanStart, limit, MetricAffectingSpan.class) - mStart;
            if (spanLimit >= target) {
                break;
            }
            spanStart = spanLimit;
        }
        MetricAffectingSpan[] spans = mSpanned.getSpans(mStart + spanStart, mStart + spanLimit, MetricAffectingSpan.class);
        spans = TextUtils.removeEmptySpans(spans, mSpanned, MetricAffectingSpan.class);
        if (spans.length > 0) {
            ReplacementSpan replacement = null;
            for (int j = 0; j < spans.length; j++) {
                MetricAffectingSpan span = spans[j];
                if (span instanceof ReplacementSpan) {
                    replacement = (ReplacementSpan) span;
                } else {
                    span.updateMeasureState(wp);
                }
            }
            if (replacement != null) {
                // the start or end of this span.
                return after ? spanLimit : spanStart;
            }
        }
    }
    int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
    int cursorOpt = after ? Paint.CURSOR_AFTER : Paint.CURSOR_BEFORE;
    if (mCharsValid) {
        return wp.getTextRunCursor(mChars, spanStart, spanLimit - spanStart, flags, offset, cursorOpt);
    } else {
        return wp.getTextRunCursor(mText, mStart + spanStart, mStart + spanLimit, flags, mStart + offset, cursorOpt) - mStart;
    }
}
Also used : ReplacementSpan(android.text.style.ReplacementSpan) Paint(android.graphics.Paint) MetricAffectingSpan(android.text.style.MetricAffectingSpan)

Example 3 with ReplacementSpan

use of android.text.style.ReplacementSpan in project android_frameworks_base by ParanoidAndroid.

the class MeasuredText method addStyleRun.

float addStyleRun(TextPaint paint, MetricAffectingSpan[] spans, int len, Paint.FontMetricsInt fm) {
    TextPaint workPaint = mWorkPaint;
    workPaint.set(paint);
    // XXX paint should not have a baseline shift, but...
    workPaint.baselineShift = 0;
    ReplacementSpan replacement = null;
    for (int i = 0; i < spans.length; i++) {
        MetricAffectingSpan span = spans[i];
        if (span instanceof ReplacementSpan) {
            replacement = (ReplacementSpan) span;
        } else {
            span.updateMeasureState(workPaint);
        }
    }
    float wid;
    if (replacement == null) {
        wid = addStyleRun(workPaint, len, fm);
    } else {
        // Use original text.  Shouldn't matter.
        wid = replacement.getSize(workPaint, mText, mTextStart + mPos, mTextStart + mPos + len, fm);
        float[] w = mWidths;
        w[mPos] = wid;
        for (int i = mPos + 1, e = mPos + len; i < e; i++) w[i] = 0;
        mPos += len;
    }
    if (fm != null) {
        if (workPaint.baselineShift < 0) {
            fm.ascent += workPaint.baselineShift;
            fm.top += workPaint.baselineShift;
        } else {
            fm.descent += workPaint.baselineShift;
            fm.bottom += workPaint.baselineShift;
        }
    }
    return wid;
}
Also used : ReplacementSpan(android.text.style.ReplacementSpan) Paint(android.graphics.Paint) MetricAffectingSpan(android.text.style.MetricAffectingSpan)

Example 4 with ReplacementSpan

use of android.text.style.ReplacementSpan in project platform_frameworks_base by android.

the class TextLine method handleRun.

/**
     * Utility function for handling a unidirectional run.  The run must not
     * contain tabs but can contain styles.
     *
     *
     * @param start the line-relative start of the run
     * @param measureLimit the offset to measure to, between start and limit inclusive
     * @param limit the limit of the run
     * @param runIsRtl true if the run is right-to-left
     * @param c the canvas, can be null
     * @param x the end of the run closest to the leading margin
     * @param top the top of the line
     * @param y the baseline
     * @param bottom the bottom of the line
     * @param fmi receives metrics information, can be null
     * @param needWidth true if the width is required
     * @return the signed width of the run based on the run direction; only
     * valid if needWidth is true
     */
private float handleRun(int start, int measureLimit, int limit, boolean runIsRtl, Canvas c, float x, int top, int y, int bottom, FontMetricsInt fmi, boolean needWidth) {
    // Case of an empty line, make sure we update fmi according to mPaint
    if (start == measureLimit) {
        TextPaint wp = mWorkPaint;
        wp.set(mPaint);
        if (fmi != null) {
            expandMetricsFromPaint(fmi, wp);
        }
        return 0f;
    }
    if (mSpanned == null) {
        TextPaint wp = mWorkPaint;
        wp.set(mPaint);
        final int mlimit = measureLimit;
        return handleText(wp, start, limit, start, limit, runIsRtl, c, x, top, y, bottom, fmi, needWidth || mlimit < measureLimit, mlimit);
    }
    mMetricAffectingSpanSpanSet.init(mSpanned, mStart + start, mStart + limit);
    mCharacterStyleSpanSet.init(mSpanned, mStart + start, mStart + limit);
    // Shaping needs to take into account context up to metric boundaries,
    // but rendering needs to take into account character style boundaries.
    // So we iterate through metric runs to get metric bounds,
    // then within each metric run iterate through character style runs
    // for the run bounds.
    final float originalX = x;
    for (int i = start, inext; i < measureLimit; i = inext) {
        TextPaint wp = mWorkPaint;
        wp.set(mPaint);
        inext = mMetricAffectingSpanSpanSet.getNextTransition(mStart + i, mStart + limit) - mStart;
        int mlimit = Math.min(inext, measureLimit);
        ReplacementSpan replacement = null;
        for (int j = 0; j < mMetricAffectingSpanSpanSet.numberOfSpans; j++) {
            // empty by construction. This special case in getSpans() explains the >= & <= tests
            if ((mMetricAffectingSpanSpanSet.spanStarts[j] >= mStart + mlimit) || (mMetricAffectingSpanSpanSet.spanEnds[j] <= mStart + i))
                continue;
            MetricAffectingSpan span = mMetricAffectingSpanSpanSet.spans[j];
            if (span instanceof ReplacementSpan) {
                replacement = (ReplacementSpan) span;
            } else {
                // We might have a replacement that uses the draw
                // state, otherwise measure state would suffice.
                span.updateDrawState(wp);
            }
        }
        if (replacement != null) {
            x += handleReplacement(replacement, wp, i, mlimit, runIsRtl, c, x, top, y, bottom, fmi, needWidth || mlimit < measureLimit);
            continue;
        }
        for (int j = i, jnext; j < mlimit; j = jnext) {
            jnext = mCharacterStyleSpanSet.getNextTransition(mStart + j, mStart + inext) - mStart;
            int offset = Math.min(jnext, mlimit);
            wp.set(mPaint);
            for (int k = 0; k < mCharacterStyleSpanSet.numberOfSpans; k++) {
                // Intentionally using >= and <= as explained above
                if ((mCharacterStyleSpanSet.spanStarts[k] >= mStart + offset) || (mCharacterStyleSpanSet.spanEnds[k] <= mStart + j))
                    continue;
                CharacterStyle span = mCharacterStyleSpanSet.spans[k];
                span.updateDrawState(wp);
            }
            // Only draw hyphen on last run in line
            if (jnext < mLen) {
                wp.setHyphenEdit(0);
            }
            x += handleText(wp, j, jnext, i, inext, runIsRtl, c, x, top, y, bottom, fmi, needWidth || jnext < measureLimit, offset);
        }
    }
    return x - originalX;
}
Also used : ReplacementSpan(android.text.style.ReplacementSpan) Paint(android.graphics.Paint) MetricAffectingSpan(android.text.style.MetricAffectingSpan) CharacterStyle(android.text.style.CharacterStyle)

Example 5 with ReplacementSpan

use of android.text.style.ReplacementSpan in project platform_frameworks_base by android.

the class TextLine method getOffsetBeforeAfter.

/**
     * Returns the next valid offset within this directional run, skipping
     * conjuncts and zero-width characters.  This should not be called to walk
     * off the end of the line, since the returned values might not be valid
     * on neighboring lines.  If the returned offset is less than zero or
     * greater than the line length, the offset should be recomputed on the
     * preceding or following line, respectively.
     *
     * @param runIndex the run index
     * @param runStart the start of the run
     * @param runLimit the limit of the run
     * @param runIsRtl true if the run is right-to-left
     * @param offset the offset
     * @param after true if the new offset should logically follow the provided
     * offset
     * @return the new offset
     */
private int getOffsetBeforeAfter(int runIndex, int runStart, int runLimit, boolean runIsRtl, int offset, boolean after) {
    if (runIndex < 0 || offset == (after ? mLen : 0)) {
        // return accurate values.  These are a guess.
        if (after) {
            return TextUtils.getOffsetAfter(mText, offset + mStart) - mStart;
        }
        return TextUtils.getOffsetBefore(mText, offset + mStart) - mStart;
    }
    TextPaint wp = mWorkPaint;
    wp.set(mPaint);
    int spanStart = runStart;
    int spanLimit;
    if (mSpanned == null) {
        spanLimit = runLimit;
    } else {
        int target = after ? offset + 1 : offset;
        int limit = mStart + runLimit;
        while (true) {
            spanLimit = mSpanned.nextSpanTransition(mStart + spanStart, limit, MetricAffectingSpan.class) - mStart;
            if (spanLimit >= target) {
                break;
            }
            spanStart = spanLimit;
        }
        MetricAffectingSpan[] spans = mSpanned.getSpans(mStart + spanStart, mStart + spanLimit, MetricAffectingSpan.class);
        spans = TextUtils.removeEmptySpans(spans, mSpanned, MetricAffectingSpan.class);
        if (spans.length > 0) {
            ReplacementSpan replacement = null;
            for (int j = 0; j < spans.length; j++) {
                MetricAffectingSpan span = spans[j];
                if (span instanceof ReplacementSpan) {
                    replacement = (ReplacementSpan) span;
                } else {
                    span.updateMeasureState(wp);
                }
            }
            if (replacement != null) {
                // the start or end of this span.
                return after ? spanLimit : spanStart;
            }
        }
    }
    int dir = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
    int cursorOpt = after ? Paint.CURSOR_AFTER : Paint.CURSOR_BEFORE;
    if (mCharsValid) {
        return wp.getTextRunCursor(mChars, spanStart, spanLimit - spanStart, dir, offset, cursorOpt);
    } else {
        return wp.getTextRunCursor(mText, mStart + spanStart, mStart + spanLimit, dir, mStart + offset, cursorOpt) - mStart;
    }
}
Also used : ReplacementSpan(android.text.style.ReplacementSpan) Paint(android.graphics.Paint) MetricAffectingSpan(android.text.style.MetricAffectingSpan)

Aggregations

Paint (android.graphics.Paint)43 ReplacementSpan (android.text.style.ReplacementSpan)43 MetricAffectingSpan (android.text.style.MetricAffectingSpan)22 CharacterStyle (android.text.style.CharacterStyle)8 TextPaint (android.text.TextPaint)2